2011-05-25 13 views
6

Tengo navegación principal y navegación secundaria que por motivos de diseño están en DIV separados. Me gustaría mostrar el subnave apropiado cuando se sitúa un elemento de navegación principal, lo que puedo hacer, pero también quiero mantener el subnave abierto si el usuario mueve el mouse fuera del elemento de navegación principal y hacia el sub -nav área. La última parte es el lugar donde me estoy estancando.jQuery hover depende de dos elementos

Estoy pensando en salir, tengo que hacer algo con setTimeout() y una instrucción IF, pero no he podido hacer ningún progreso en esa área. ¿Es incluso un enfoque que vale la pena intentar?

HTML:

<div id="mnav"> 
<ul id="buttons"> 
    <li class="one"><a href="#">Main 1</a></li> 
    <li class="two"><a href="#">Main 2</a></li> 
    <li class="three"><a href="#">Main 3</a></li> 
    <li class="four nav-dark"><a href="#">Main 4</a></li> 
</ul> 
</div> <!-- /mnav --> 

<div id="snav"> 
<ul class="snav-one"> 
    <li><a href="#">Sub 1.1</a></li> 
    <li><a href="#">Sub 1.2</a></li> 
    <li><a href="#">Sub 1.3</a></li> 
    <li><a href="#">Sub 1.4</a></li> 
    <li><a href="#">Sub 1.5</a></li> 
    <li><a href="#">Sub 1.6</a></li> 
</ul> 
<ul class="snav-two"> 
    <li><a href="#">Sub 2.1</a></li> 
    <li><a href="#">Sub 2.2</a></li> 
</ul> 
</div> <!-- /snav --> 

JS:

$(document).ready(function() { 
$("#buttons li.one, #buttons li.two").hover(function(){ 
    var subnav = 'ul.snav-' + $(this).attr('class'); 

    $("#snav").slideDown('fast').addClass("open").find(subnav).show(); 

}, function(e){ 
    var subnav = 'ul.snav-' + $(this).attr('class'); 

    $("#snav").slideUp('fast').removeClass("open").find(subnav).hide(); 
}); 
}); 

Respuesta

8

Para la ergonomía del ratón-menú que desea una pequeña demora mientras pasar el ratón de la principal a submenús, por lo que el sub el menú no se cierra antes de que el mouse llegue allí. (Como dice la pregunta.)

Pero, también es necesario un retraso antes de abrir menús - tanto para evitar la activación molesto "paso elevado", y para reducir la ocurrencia común de cambiar accidentalmente de SUB1 a sub2 mientras moviéndose fuera del menú principal.

Por lo tanto, el código pregunta necesita:

  1. hover sobre el submenú ul elementos.
  2. stop para detener la ejecución de animaciones si la selección del mouse cambia.
  3. Un temporizador reiniciable que controla tanto abrir como cerrar.

See the demo at jsFiddle.

Poniendo todo junto:

$("#buttons li.one, #buttons li.two").hover (function() { MenuOpenCloseErgoTimer (
     100, 
     function (node) { 
      var subnav = 'ul.snav-' + $(node).attr ('class'); 
      $("#snav ul").hide(); 
      $("#snav").stop (true, true).slideDown ('fast').addClass ("open").find (subnav).show(); 
     }, 
     this 
    ); }, 
    function() { MenuOpenCloseErgoTimer (
     200, 
     function() { 
      $("#snav").stop (true, true).slideUp ('fast').removeClass ("open").find ('ul').hide(); 
     } 
    ); } 
); 

$("div#snav ul").hover (function() { MenuOpenCloseErgoTimer (
     0, 
     function() { 
      $("#snav").stop (true, true).slideDown ('fast').addClass ("open"); 
      $(this).show(); 
     } 
    ); }, 
    function() { MenuOpenCloseErgoTimer (
     200, 
     function() { 
      $("#snav").stop (true, true).slideUp ('fast').removeClass ("open"); 
      $("#snav ul").hide(); 
     } 
    ); } 
); 

function MenuOpenCloseErgoTimer (dDelay, fActionFunction, node) { 
    if (typeof this.delayTimer == "number") { 
     clearTimeout (this.delayTimer); 
     this.delayTimer = ''; 
    } 
    if (node) 
     this.delayTimer  = setTimeout (function() { fActionFunction (node); }, dDelay); 
    else 
     this.delayTimer  = setTimeout (function() { fActionFunction(); }, dDelay); 
} 



Nota las operaciones adicionales requeridas en #snav ul, a la limpieza después de permutas interrumpidas entre los submenús.

+2

¡Eso funcionó perfectamente! Muchas gracias por tomarse el tiempo para unir eso, realmente me estás ayudando Y enseñándome muchísimo. – creativetim

+1

De nada. ¡Encantado de ayudar! –

+0

No quiero estirarlo, pero ¿tiene alguna idea sobre la refactorización para permitir que un subnav se abra en una página de forma predeterminada? – creativetim

4

En lugar de utilizar el método .hover(), pruebe a utilizar controladores de eventos separados para MouseEnter y mouseleave. El mouseenter solo se adjuntaría a los botones mnav, mientras que el mouseleave se adjuntaría tanto al botón mnav como al snav div. En las funciones de alejamiento del mouse, probablemente tendrá que agregar un pequeño tiempo de espera y verificar si pasaron de un elemento a otro.

intentar algo como esto:

<script> 
    var timer; 
    $(document).ready(function() { 
     $("#mnav").mouseenter(function() { 
      $("#snav").slideDown(); 
     }); 

     $("#mnav, #snav").mouseleave(function() { 
      timer=setTimeout("$('#snav').slideUp();",50); 
     }); 

     $("#mnav, #snav").mouseenter(function() { 
      clearTimeout(timer); 
     }); 
    }); 
</script> 
+0

¿Puede darme un ejemplo del controlador de eventos mouseleave, incluso si es un pseudo código? – creativetim

+0

Avíseme si ese código agregado tiene sentido. –

+0

@TNguyen este código funcionaba como un encanto, corto y dulce. – Codex73

1

See example →

Lo que sigue debe trabajar para usted, hice varios cambios:

  • utilizó el .stop() method para detener la animación al entrar en la subnav
  • movió las diapositivas al subnav ul's en lugar del contenedor por lo que lo anterior trabajar
  • algunas otras cosas

ver más abajo:

$("#buttons li.one, #buttons li.two").hover(function() { 
    var subnav = 'ul.snav-' + $(this).attr('class'); 

    $("#snav").find('ul').slideUp('fast'); 
    $("#snav").addClass("open").find(subnav).stop(true, true).slideDown('fast'); 
}, function(e) { 
    var subnav = 'ul.snav-' + $(this).attr('class'); 

    $("#snav").removeClass("open").find(subnav).slideUp('fast'); 
}); 

$('#snav').bind('mouseenter', function(e) { 
    $(this).find('ul').stop(true, false); 
}).bind('mouseleave', function(e) { 
    $(this).find('ul').stop(true, true).slideUp('fast'); 
}); 

See example →