8

I have a menu-submenu-subsubmenu construction in HTML like this:

<menu>
    <li><a href="...">Item 1</a></li>
    <li><ul>
            <li><a href="...">Subitem 1</a></li>
            <li><a href="...">Subitem 2</a></li>
            <li><ul>
                    <li><a href="...">Sub-subitem 1</a></li>
                    <li><a href="...">Sub-subitem 2</a></li>
                    <li><a href="...">Sub-subitem 3</a></li>
                </ul>
                <a href="...">Subitem 3</a></li>
            <li><a href="...">Subitem 4</a></li>
        </ul>
        <a href="...">Item 2</a>
    </li>
    <li><a href="...">Item 3</a></li>
    <li><a href="...">Item 4</a></li>

...using whit this css formating:

menu {
    display: block;
    width: 200px;
}
/* hide subitems */
menu li ul,
menu li ul li ul {
    display: none;
    position: absolute;
}
/* set up positions */
menu li ul {
    left: 200px;
    width: 200px;
}
menu li ul li ul {
    left: 400px;
    width: 200px;
}

I use this jQuery code:

$(function() {
    /* hide all submenu */
    $('menu').find('ul').hide();
    /* show submenu on mouseenter */
    $('menu li a').mouseenter(function() {
        $(this).parent().children('ul').show();
    }).mouseleave(function() {
        $(this).parent().children('ul').hide();
    });
});

How can I detect mouse is leaving the element to their child? Or how can I get the child element to stay if it's necessary?

netdjw
  • 5,419
  • 21
  • 88
  • 162
  • won't you need the same thing like `menu > ul > li > ul` – Mr. Alien Jan 07 '14 at 12:50
  • I think not the tag names is the essence. Change it to ` – netdjw Jan 07 '14 at 12:54
  • 1
    Does this help? http://jsfiddle.net/xSN2S/ – naththedeveloper Jan 07 '14 at 13:01
  • Your HTML is invalid. A `li` should be within a `ul`. – putvande Jan 07 '14 at 13:21
  • 1
    Your HTML is invalid, but not because of what @putvande or @Mr. Alien have said. [To fix it, you need to add a `[type="toolbar"]` attribute to your `` element](http://www.w3.org/html/wg/drafts/html/master/single-page.html#the-menu-element). Alternatively, if your menu is meant to contain navigational links, rather than interactive javascript driven controls for a web application, [you should be using the ` – zzzzBov Jan 08 '14 at 03:22

2 Answers2

4

Change your code to be like this:

$(function() {
/* hide all submenu */
$('menu').find('ul').hide();
/* show submenu on mouseenter */ 

// here, just select the direct child
$('menu').find('li > a, li > ul').mouseenter(function() {
    var time = new Date().getTime();
    $(this).parent().find('ul').show().data('showing-time', time);
}).mouseleave(function() {
    var leaveTime = new Date().getTime();
    var $this = $(this);
    window.setTimeout(function () {
        var $ul = $this.parent().find('ul');
        var beginTime = $ul.data('showing-time') || 0;
        if (leaveTime > beginTime) {
            $this.parent().find('ul').hide().data('showing-time', 0);
        }
    }, 100);
});
});

Hope this helps.

update
Code updated.

I suggest just put the sub menus next to the parent menu item(here, means li > a element) to get a better result.

  • Good idea, but this solution hide the subitem before mouse can enter into there. – netdjw Jan 07 '14 at 20:23
  • In `.mouseleave` section need to check where is the mouse... in a child/sibling element or anywhere else? Can I do this somehow? – netdjw Jan 07 '14 at 20:25
2

Here's how I would go about it. You don't need javascript at all, at least not for simple hiding/showing. But, if you want to add delays, I would strongly suggest using jquery only to add/remove appropriate css classes with a settimeout.

css:

.menu {
    position: relative;
    display: inline-block;
}

.submenu {
    display: none;
    position: absolute;
    left: 100%;
}

.menu li:hover > .submenu, .submenu.show {
  display: inline-block;
}

html:

<ul class="menu">
    <li><a href="...">Item 1</a></li>
    <li><ul class="submenu">
            <li><a href="...">Subitem 1</a></li>
            <li><a href="...">Subitem 2</a></li>
            <li><ul class="submenu">
                    <li><a href="...">Sub-subitem 1</a></li>
                    <li><a href="...">Sub-subitem 2</a></li>
                    <li><a href="...">Sub-subitem 3</a></li>
                </ul>
                <a href="...">Subitem 3</a></li>
            <li><a href="...">Subitem 4</a></li>
        </ul>
        <a href="...">Item 2</a>
    </li>
    <li><a href="...">Item 3</a></li>
    <li><a href="...">Item 4</a></li>
</ul>

js:

$('body').on('mouseleave','.submenu', function(e) {

    var jTarget = $(e.currentTarget).addClass('show');

    setTimeout(function() {
            jTarget.removeClass('show');
    }, 500);
})

Check out this jsfiddle with the js delay: http://jsfiddle.net/LxL4N/1/

bearfriend
  • 10,322
  • 3
  • 22
  • 28