2010-08-19 16 views
10

Estoy en proceso de aprender Javascript y estoy intentando crear un menú desplegable simple. Un ejemplo de mi funcionalidad deseada se puede ver en la página de inicio de google en el menú superior con el menú desplegable "más" y "configuraciones". Específicamente, cuando hace clic en el menú, el menú desaparece.Cuerpo de Javascript OnClick

¿Qué código debo colocar en la función hideMenus en Javascript para ocultar los uls visibles cuando se produce un clic en algún lugar de la pantalla?

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

No quiero usar jQuery.

+6

upvoted para "No quiero usar jQuery" –

Respuesta

1

Parece que tiene una configuración bastante decente tal como está. Es probable que se encuentre con algunos problemas de burbujas de eventos (para obtener más información, consulte PPK's Event Order Article). Eso parece estar fuera del alcance de su pregunta actual, por lo que sólo le voy a dar lo que pidieron:

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

En primer lugar, tenemos todas las <ul> 's en la página. Luego, recorremos todos ellos, verificamos si es un submenú y si se muestra actualmente. Si ambos son verdaderos, entonces lo ocultamos.

Hay un par de fallos con este código:

  • Si los ULS tienen más de una clase (class="animal submenu"), entonces no va a ocultar el menú
  • que se verá a través todo la <ul> en la página. Esto no es exactamente eficiente, pero es la única manera de hacerlo sin compatibilidad con navegadores cruzados para getElementsByClass.

Estas no son fallas enormes, especialmente si solo está usando esto para aprender acerca de Javascript, y si controla de cerca su código (es decir, ningún otro desarrollador está trabajando en ello). En general, es un buen trampolín.

En el futuro, sugiero usar addEvent - una función bastante común que le permite agregar controladores de eventos a elementos sin usar onclick="...". Hay un par de implementaciones diferentes de él, pero (casi) todos funcionan de la misma manera desde su perspectiva. Aquí hay enlaces a Dean Edwards's Version y John Resig's Version

¡Buena suerte!

+1

'getElementsByTagName' – lincolnk

+0

¡Vaya! Buena atrapada. Solucionado, y +1 –

-1

Puede capturar un clic en cualquier lugar si hace clic en el cuerpo. Debido al modelo de propagación de eventos de JavaScript, si hace clic en cualquier elemento de un elemento y no detiene la propagación del evento, alcanzará el cuerpo y ocultará los menús.

Así que, básicamente, esto significa que desea capturar cuerpo haciendo clic y ocultar los menús para que cuando haga clic en cualquier área de la página, cierre los menús.

Pero esto oculta un poco de comportamiento no deseado: al hacer clic en el botón para mostrar el menú, el menú se mostrará y rápidamente después de esa ocultación (cuando el evento llegue al cuerpo). Para evitar esto, querrá evitar que el evento se propague cuando haga clic en el botón que muestra el menú (puede ver cómo funciona esto en el código que publiqué a continuación). El código muestra dónde debe tocar para que funcione bien.

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

Ahora la parte más importante.

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 
} 

Y, finalmente, en toda su elemento UL:

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

Para explicar una vez más lo que esto hace:

primero. Conecta su función hideMenu a body.onclick. Esto significa que siempre ocultará los menús si no paramos el evento.

2do. Cuando hace clic en el botón de menú, muestra el menú y luego dejamos que el evento vaya al cuerpo. De esta forma, body.onclick no se disparará y no ocultará el menú justo después de que lo hayamos abierto.

3er. El clic de ul significa que el menú no se ocultará cuando hagamos clic en él (aunque si desea que el menú se oculte al hacer clic en el menú, puede eliminar esta parte).

+0

Está definiendo 'stop_event' con el parámetro' e', pero no lo llama con un parámetro de evento? –

+0

E no es necesario, como puede ver. Además, si observa detenidamente el código, hace exactamente lo que quería: ocultar los menús si hace clic en cualquier lugar de la pantalla (si se refiere a la página web, no al sistema operativo o al marco del navegador), porque enganchó hideMenu en el cuerpo hacer clic. En cuanto a la última parte ... la editaré ahora, realmente parece estúpida después de leerla una vez más. – bisko

+0

Vaya, pasó por alto la parte con 'onclick =" hideMenus(); "'. 'e' es necesario, ya que' window.event' solo es compatible con IE. Pero cuando se usan manejadores de eventos en línea DOM nivel 0 (en navegadores no IE), la interfaz 'event' se pasa como un parámetro a una función * wrapper *, por lo que' e' es [inaccesible] (https: //developer.mozilla .org/es/DOM/element # Event_Handlers). También vea [JSBin] (http://jsbin.com/imuwo3/2/edit) para probar. Por lo tanto, detener el burbujeo de eventos de esta manera no es posible. Sobre la explicación: de hecho, esto está mucho más claro ahora. –

0

aquí es más o menos la lógica que usamos en nuestra aplicación web para menús desplegables:

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

El truco consiste en utilizar un campo input que tiene el focus, y cuando se pierde es un onblur es activó y cerró el menú.

mouseover, mouseout están ahí para evitar que el onblur se dispare cuando el usuario hace clic en un elemento en el menú.

Para tener un efecto de alternar como un abrir/cerrar en el enlace, supongo que se necesitan 2 enlaces que se esconden entre sí.

Cuestiones relacionadas