I've created a custom jQuery horizontal menu with drop downs. Initially it just faded a sub-menu in when hovering on a list item, and faded it out when moving away.
However I want to create an effect where if you move the mouse out of the sub-menu, it doesn't disappear instantly (e.g. if you overshoot it by a pixel). I was made aware of the hoverIntent plugin in a previous question, but it has an annoying delay when opening sibling sub-menus. So I started from scratch with my own functionality in mind.
My HTML is a standard nested list, ul#menu > li > ul > li. My Javascript is as follows:
var menuVisible = false;
var cancelTimeout = false;
$(document).ready(function(){
$('ul#menu > li').hover(
function(){
menuMouseOver( $(this) );
},
function(){
menuMouseOut( $(this) );
}
);
});
function menuMouseOver( $li )
{
// if one of the menus is down, check which one we're hovering
if ( menuVisible ) {
cancelTimeout = true;
if ( $li.find('>ul').css('display') == 'block' ) {
// do nothing if we're hovering over current menu
}
else {
// turn off all menus
$li.parent().find('>li').each( function() {
menuOff( $li )
});
}
}
menuOn( $li );
menuVisible = true;
}
function menuMouseOut( $li )
{
setTimeout(
function(){
if ( !cancelTimeout ) {
menuOff( $li );
menuVisible = false;
}
cancelTimeout = false;
},
2000
);
}
function menuOn( $li )
{
$li.css('background-position', 'left bottom');
$li.find('>ul').fadeIn('fast');
}
function menuOff( $li )
{
$li.css('background-position', 'left top');
$li.find('>ul').fadeOut('fast');
}
The following things work:
- Moving over a top-level
li
opens the sub-menu. - Moving away from the sub-menu closes it after 2 seconds (for testing purposes; will be reduced in the final version).
- Moving away from the sub-menu and back cancels the timeout and therefore stops the menu from disappearing
However, these don't work:
- When moving from one top-level list item to the next, the previous sub-menu doesn't disappear. I want it to fade out straight away, without the normal delay.
- If I move across two top-level list items,
menuVisible
is set tofalse
, which screws up the system. This is becausecancelTimeout
is set to true when you move over the first sibling, and it is still true as you move to the second sibling.
I'd appreciate any insight into why this happens, and of course, how to fix it.