如何在jQuery中检测鼠标是否悬停在子元素上?

8

我在HTML中有一个菜单-子菜单-子子菜单的结构,像这样:

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

使用以下 CSS 格式:

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

我使用这个jQuery代码:

$(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();
    });
});

我该如何检测鼠标是否离开了元素并进入了它的子元素?或者如果需要,我该如何保持子元素的状态?

你不需要像 menu > ul > li > ul 这样的东西吗? - Mr. Alien
我认为标签名称并不是关键。如果出现问题,将其更改为“<nav>”。;) - netdjw
1
这个有帮助吗?http://jsfiddle.net/xSN2S/ - naththedeveloper
您的HTML无效。li应该在ul内部。 - putvande
1
你的HTML无效,但不是因为@putvande或@Mr.Alien所说的。要修复它,您需要将[type="toolbar"]属性添加到您的<menu>元素中。或者,如果您的菜单旨在包含导航链接,而不是用于Web应用程序的交互式JavaScript驱动控件,您应该使用带有<ul><ol>子元素的<nav>元素 - zzzzBov
2个回答

4
将您的代码更改为以下形式:
$(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);
});
});

希望这有所帮助。

更新
代码已更新。

我建议将子菜单放在父菜单项旁边(这里指li > a元素),以获得更好的效果。


好主意,但是这个解决方案会在鼠标进入子项之前隐藏它们。 - netdjw
.mouseleave 部分需要检查鼠标在哪里...是在子元素/同级元素还是其他地方?我能做到这点吗? - netdjw

2
这是我会处理的方式。对于简单的隐藏/显示,您根本不需要使用JavaScript。但是,如果您想添加延迟,我强烈建议仅使用jQuery来添加/删除适当的CSS类,并使用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);
})

请查看这个带有JavaScript延迟的jsfiddle示例: http://jsfiddle.net/LxL4N/1/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接