2010-08-19 49 views
10

Tôi đang trong quá trình tìm hiểu Javascript và tôi đang cố tạo một menu thả xuống đơn giản. Một ví dụ về chức năng mong muốn của tôi có thể được nhìn thấy trên trang chủ google trong trình đơn trên cùng với menu thả xuống "nhiều hơn" và "cài đặt". Cụ thể khi bạn nhấp vào menu, menu sẽ biến mất.Nội dung Javascript OnClick

Tôi cần đặt mã nào vào hàm hideMenus trong Javascript để ẩn các dấu nháy hiển thị khi một lần nhấp xuất hiện ở bất kỳ đâu trên màn hình?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 

<head> 
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> 
<title>Untitled 1</title> 

<style type="text/css"> 
a 
{ 
    color:blue; 
} 

.info ul.submenu 
{ 
    border: solid 1px #e0e0e0; 
    background-color: #fff; 
    position: absolute; 
    padding: 0; 
    z-index: 2; 
    display: none; 
} 

.info ul.submenu li 
{ 
    display: block; 
    border-top: solid 1px #e0e0e0; 
    margin: 0px 10px 0 10px; 
} 

.info ul.submenu li a 
{ 
    display: block; 
    padding: 7px 0px 6px 0; 
    color: #1177ee; 
    cursor:pointer; 
} 

</style> 

<script type="text/javascript"> 

function hideMenus() 
{ 
//TODO 
} 

function menu(id) {  
    var myLayer = document.getElementById(id);  

    myLayer.onblur = function() {  
     myLayer.style.display = 'none'; 
    }; 

    if (myLayer.style.display == "none" || myLayer.style.display == "") {  
     myLayer.style.display = "block";  
    } else {  
     myLayer.style.display = "none";  
    }  
} 

</script> 
</head> 

<body onclick="hideMenus();"> 
<div class="info">  
    Some Text Boom A <a onclick="menu('id1');">Link</a> | More text  
    <a onclick="menu('id2');">Another Link</a> | more text  
    <ul id="id1" class="submenu">  
     <li><a href="dfhdfh">A1</a></li>  
     <li><a href="aetjetjsd">A2 This is Long</a></li>  
     <li><a href="etetueb">A3</a></li>  
    </ul>  
    <ul id="id2" class="submenu">  
     <li><a href="dfhdfh">B1</a></li>  
     <li><a href="aetjetjsd">B2</a></li>  
     <li><a href="etetueb">B3</a></li>  
    </ul>  
    </div>  
</body> 
</html> 

Tôi không muốn sử dụng jQuery.

+6

upvoted cho "Tôi không muốn sử dụng jQuery" –

Trả lời

1

Có vẻ như bạn đã thiết lập khá tốt. Bạn có thể sẽ gặp phải một số sự cố sủi bọt (để biết thêm thông tin, hãy xem PPK's Event Order Article). Đó có vẻ là ngoài phạm vi của câu hỏi hiện tại của bạn, vì vậy tôi sẽ chỉ cung cấp cho bạn những gì bạn yêu cầu:

hideMenus() 
{ 
    var uls = document.getElementsByTagName('ul'), i; 
    for (i = 0; i < uls.length; i++) 
    { 
     if (uls[i].className === 'submenu' && uls[i].style.display !== 'none') 
     { 
      uls[i].style.display = 'none'; 
     } 
    } 
} 

Đầu tiên, chúng tôi nhận được tất cả các <ul> 's trên trang. Sau đó, chúng ta lặp qua tất cả chúng, kiểm tra xem đó có phải là menu con hay không và nếu nó hiện đang được hiển thị. Nếu cả hai đều đúng, thì chúng ta sẽ ẩn nó đi.

Có một vài lỗi với mã này:

  • Nếu uls có nhiều hơn một lớp (class="animal submenu"), sau đó nó sẽ không ẩn menu
  • Nó sẽ xem xét thông qua tất cả các <ul> 's trên trang. Điều này không chính xác hiệu quả, nhưng đó là cách duy nhất để thực hiện điều đó mà không cần hỗ trợ qua trình duyệt cho getElementsByClass.

Đây không phải là lỗi lớn, đặc biệt nếu bạn chỉ sử dụng điều này để tìm hiểu về javascript và nếu bạn kiểm soát chặt chẽ mã của mình (nghĩa là không có nhà phát triển nào khác đang làm việc trên đó). Tất cả trong tất cả, đó là một bước đệm tốt.

Trong tương lai, tôi khuyên bạn nên sử dụng addEvent - một chức năng khá phổ biến cho phép bạn thêm trình xử lý sự kiện vào các phần tử mà không cần sử dụng onclick="...". Có một vài triển khai khác nhau của nó, nhưng chúng (hầu như) tất cả đều làm việc giống nhau từ quan điểm của bạn. Đây là các liên kết đến Dean Edwards's VersionJohn Resig's Version

Chúc may mắn!

+1

'getElementsByTagName' – lincolnk

+0

Rất tiếc! Nắm bắt tốt. Đã sửa lỗi và +1 –

-1

Bạn có thể chụp một nhấp chuột ở bất kỳ đâu nếu bạn đặt onclick trên cơ thể. Do mô hình tuyên truyền sự kiện javascript, nếu bạn nhấp vào bất kỳ đâu trên bất kỳ phần tử nào và bạn không ngăn sự kiện lan truyền, nó sẽ tiếp cận nội dung và ẩn các menu. Vì vậy, về cơ bản điều này có nghĩa là bạn muốn chụp cơ thể và nhấp vào để ẩn các menu để khi bạn nhấp vào bất kỳ vùng nào của trang, nó sẽ đóng các menu.

Nhưng điều này ẩn một chút hành vi không mong muốn - khi bạn bấm vào nút để hiển thị menu, trình đơn sẽ hiển thị và nhanh chóng sau khi ẩn đó (khi sự kiện đến cơ thể). Để ngăn chặn điều này, bạn sẽ muốn ngăn sự kiện này lan truyền khi bạn nhấp vào nút hiển thị menu (bạn có thể xem cách hoạt động của mã này trong mã tôi đã đăng bên dưới). Mã cho thấy nơi bạn cần chạm để làm cho nó hoạt động độc đáo.

// this function stops event e or window.event if e is not present from 
// propagating to other elements. 
function stop_event(e) { 
    if(!e) { 
     e = window.event; 
    } 
    if (e.stopPropagation) e.stopPropagation(); 
    e.cancelBubble = true; 
    if (e.preventDefault) e.preventDefault(); 
    e.returnValue = false; 
    return false; 
} 

// now you just hide all the menus in your hideMenus 
function hideMenus() 
{ 
    //pseudocode! 
    for all visible menus - hide // or if you want you can hide all menus, 
           // the hidden will remain hidden 
} 

Bây giờ là phần quan trọng.

function menu(id) {  
    // your stuff here 
    stop_event(); // this will stop the event going down to the body 
        // and hiding it after showing it 
        // this means it will not flicker like: show-hide 
} 

Và cuối cùng vào yếu tố toàn UL của bạn:

//partly pesudocode 
ul.onclick = function() { stop_event(); } 

Để giải thích một lần nữa điều này không:

1st. Bạn móc hàm hideMenu của bạn vào body.onclick. Điều này có nghĩa là nó sẽ luôn ẩn các menu nếu chúng ta không dừng sự kiện.

2nd. Khi bạn nhấp vào nút menu, bạn sẽ hiển thị trình đơn và sau đó chúng tôi sẽ dừng sự kiện đó khỏi phần thân. Bằng cách này, body.onclick sẽ không cháy và nó sẽ không ẩn menu ngay sau khi chúng ta mở nó.

3rd. Các ul.onclick có nghĩa là trình đơn sẽ không ẩn chính nó khi chúng ta nhấp vào nó (mặc dù nếu bạn muốn trình đơn ẩn khi bạn nhấp vào trình đơn chính nó, bạn có thể loại bỏ phần này).

+0

Bạn đang xác định 'stop_event' với tham số' e', nhưng bạn không gọi nó bằng tham số sự kiện? –

+0

E là không cần thiết như bạn có thể thấy. Ngoài ra, nếu bạn nhìn kỹ mã, nó chỉ là những gì op muốn - ẩn các menu nếu bạn nhấp vào bất cứ nơi nào trên màn hình (nếu anh ta có nghĩa là trang web của chính nó, không phải là hệ điều hành hoặc khung trình duyệt), bởi vì anh ta hook hideMenu trên cơ thể nhấp chuột. Đối với phần cuối cùng ... sẽ chỉnh sửa nó ngay bây giờ, nó thực sự có vẻ ngu ngốc sau khi đọc nó một lần nữa. – bisko

+0

Rất tiếc, bỏ qua phần với 'onclick =" hideMenus(); "'. 'e' là cần thiết, vì' window.event' chỉ được hỗ trợ bởi IE. Nhưng khi sử dụng trình xử lý sự kiện nội tuyến cấp 0 DOM (trong trình duyệt không phải IE), giao diện 'sự kiện' được chuyển thành tham số cho hàm * wrapper *, vì vậy' e' là [không thể truy cập được] (https: //developer.mozilla .org/en/DOM/phần tử # Event_Handlers). Ngoài ra, hãy xem [JSBin] (http://jsbin.com/imuwo3/2/edit) để thử. Vì vậy, dừng sự kiện bubbling theo cách này là không thể. Về giải thích: quả thực, điều này rõ ràng hơn nhiều. –

0

Sau đây là nhiều hay ít logic chúng tôi sử dụng trong ứng dụng web của chúng tôi cho trình đơn thả xuống:

<html> 
<head> 
    <title></title> 
</head> 
<body> 
    <div style="position:relative;width:250px"> 
     <a id="link" href="javascript:" onclick="showDiv(this)">Show menu</a> 
     <ul id="entries" style="display:none;background:#DEF;padding:0;margin:0"> 
     <li>item 1</li> 
     <li>item 2</li> 
     </ul> 
     <input id="inp" style="position:absolute;left:-30px;width:0" /> 
    </div> 

    <script> 
     function showDiv(lnk){ 
      var entries = document.getElementById('entries'), 
       inp = document.getElementById('inp'), 
       nh = 'data-nohide'; 
      //show the entries 
      entries.style.display = 'block'; 
      entries.removeAttribute(nh); 
      inp.focus(); 
      //if mouse over, can't close it 
      entries.onmouseover = function(){ 
       this.setAttribute(nh, true); 
       inp.focus(); 
      }; 
      //if mouse out, can close it 
      entries.onmouseout = function(){ 
       this.removeAttribute(nh); 
      }; 
      entries.onclick = function(e){ 
       //code when the user clicks on the menu... 
       alert((e.target||e.sourceElement).innerHTML); 
       this.style.display = 'none'; 
      }; 
      //if the user press ESC 
      inp.onkeyup = function(e){ 
       if(e.keyCode === 27){ 
        this.style.display = 'none'; 
        this.removeAttribute(nh); 
       }else{ 
        //do something else with other keys(ie:down, up, enter)... 
        inp.focus(); 
       } 
      }; 
      //click somewhere else input onblur 
      inp.onblur = function(){ 
       if(!entries.getAttribute(nh)){ 
        entries.style.display = 'none'; 
        entries = inp = null; 
       } 
      }; 
     } 
    </script> 
</body> 
</html> 

Bí quyết là sử dụng một trường input rằng có focus, và khi nó thua nó một onblur là kích hoạt và đóng menu.

mouseover, mouseout ở đó để ngăn chặn onblur kích hoạt khi người dùng nhấp vào một mục trong menu.

Để có hiệu ứng chuyển đổi như mở/đóng trên liên kết, tôi đoán 2 liên kết ẩn nhau là cần thiết.

Các vấn đề liên quan