Тело Javascript OnClick

Я изучаю Javascript, и я пытаюсь создать простое раскрывающееся меню. Пример моей желаемой функциональности можно увидеть на главной странице google в верхнем меню с раскрывающимся списком "больше" и "параметры". В частности, при нажатии на меню меню исчезает.

Какой код мне нужно разместить в функции hideMenus в Javascript, чтобы скрыть видимые uls, когда щелчок происходит в любом месте экрана?

<!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>   

Я не хочу использовать jQuery.

Ответ 1

Похоже, у вас довольно приличная настройка как есть. Вероятно, вы столкнетесь с некоторыми проблемами пузыря событий (для получения дополнительной информации см. статья заказа на поставку PPK). Это, кажется, выходит за рамки вашего текущего вопроса, поэтому я просто дам вам то, что вы просили:

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';
        }
    }
}

Сначала мы получаем все <ul> на странице. Затем мы перебираем все из них, проверяем, является ли это подменю, и если он отображается в настоящее время. Если оба они истинны, то мы его спрячем.

Есть пара ошибок с этим кодом:

  • Если улы имеют более одного класса (class="animal submenu"), он не будет скрывать меню
  • Он просмотрит все символы <ul> на странице. Это не совсем эффективно, но это единственный способ сделать это без поддержки кросс-браузера для getElementsByClass.

Это не огромные ошибки, особенно если вы используете только это, чтобы узнать о javascript, и если вы внимательно контролируете свой код (т.е. другие разработчики не работают над ним). В общем, это хороший ступень.

В будущем я бы предложил использовать addEvent - довольно распространенную функцию, которая позволяет добавлять обработчики событий к элементам без использования onclick="...". Есть несколько различных реализаций, но они (почти) все работают одинаково с вашей точки зрения. Здесь приведены ссылки на Версия Dean Edwards и Версия Джона Реджига

Удачи!

Ответ 2

Вот более или менее логика, которую мы используем в нашем веб-приложении для выпадающих меню:

<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>

Фокус в том, чтобы использовать поле input, которое имеет focus, а когда оно теряет его, запускается onblur и закрывает меню.

mouseover, mouseout существуют, чтобы предотвратить onblur, когда пользователь щелкает элемент в меню.

Чтобы иметь эффект переключения, например, открыть/закрыть ссылку, я думаю, нужны 2 ссылки, которые скрывают друг друга.

Ответ 3

Вы можете захватить щелчок в любом месте, если вы положите onclick на тело. Из-за модели распространения событий javascript, если вы щелкните по любому элементу и не прекращаете распространение события, он достигнет тела и скроет меню.

Таким образом, в основном это означает, что вы хотите захватить тело onclick и заставить его скрывать меню, поэтому, когда вы нажимаете на любую область страницы, он закрывает меню.

Но это скрывает немного нежелательного поведения - когда вы нажимаете на кнопку, чтобы отобразить меню, меню будет отображаться и быстро после этого скрыть (когда событие достигнет тела). Чтобы предотвратить это, вы захотите остановить распространение события при нажатии кнопки, отображающей меню (вы можете увидеть, как это работает в коде, который я разместил ниже). Код показывает, где вам нужно прикоснуться, чтобы он работал хорошо.

// 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
}

Теперь важная часть.

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
}  

И, наконец, весь ваш элемент UL:

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

Чтобы снова объяснить, что это делает:

первый. Вы подключаете функцию hideMenu к body.onclick. Это означает, что он всегда будет скрывать меню, если мы не остановим событие.

второй. Когда вы нажимаете кнопку меню, вы показываете меню, а затем мы останавливаем событие от перехода к телу. Таким образом, body.onclick не будет срабатывать, и он не скроет меню сразу после его открытия.

третий. Ul.onclick означает, что меню не будет скрываться, когда мы нажимаем на него (хотя, если вы хотите, чтобы меню скрывалось, когда вы нажимаете самое меню, вы можете удалить эту часть).