I have main navigation and sub navigation that for reasons of design are in separate DIVs. I would like to show the appropriate sub-nav when a main nav item is hovered, which I can do, but I also want to keep the sub-nav open if the user moves their mouse outside of the main nav item and into the sub-nav area. The last part is the place where I'm getting stuck.
I'm thinking on the hover out I need to do something with setTimeout() and an IF statement, but I have not been able to make any progress in that area. Is that even an approach worth trying?
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();
});
});
For Mouse-menu ergonomics you want a small delay while mousing from main to sub menus, so the the sub menu does not close before the mouse gets there. (As the question says.)
But, you also need a delay before menus open -- both to avoid annoying "flyover" activation, and to reduce the common occurrence of accidentally switching from sub1 to sub2 while moving off the main menu.
So, the question code needs:
hover
over the sub-menu ul
elements.stop
to halt running animations if mouse selection changes.See the demo at jsFiddle.
Putting it all together:
$("#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);
}
Note the extra operations required on #snav ul
, to cleanup after interrupted swaps between sub-menus.
See example →
The following should work for you, I made several changes:
.stop()
method to halt the animation on entering the subnavSee below:
$("#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 →
Instead of using the .hover() method, try using separate event handlers for mouseenter and mouseleave. The mouseenter would only be attached to the mnav buttons, while the mouseleave would be attached to both the mnav button and the snav div. On your mouseleave functions you'll probably have to add a small timeout and check to see if they went from one element to another.
Try something like this:
<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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With