You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

jQuery嵌套hover事件mouseleave移除类问题:保持子菜单始终有.active类

多级菜单交互逻辑优化

原始结构与现有问题

HTML结构

<ul class="menu-wrapper">
    <li>
        <a href="#">Menu item</a>
        <ul class="sub-menu">
            <li>
                <a href="#">Subitem-1</a>
                <ul>
                <li>Sub-Subitem-1</li>
                <li>Sub-Subitem-2</li>
                <li>Sub-Subitem-3</li>
                </ul>
            </li>
            <li>
                <a href="#">Subitem-2</a>
                <ul>
                <li>Sub-Subitem-1</li>
                <li>Sub-Subitem-2</li>
                <li>Sub-Subitem-3</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

现有jQuery实现

$('ul.menu-wrapper').children().hover(
    function() {
        let subMenu = $(this).find('ul.sub-menu').first()
        subMenu.addClass('active')
        subMenu.children().first().addClass('active')
    },
    function() {
        let subMenu = $(this).find('ul.sub-menu').first()
        subMenu.removeClass('active')
    }
)

需求与痛点

  • 新增功能:悬停ul.sub-menu内的li时,将.active类切换到当前悬停项
  • 修复问题:当前mouseleave事件会在鼠标从子菜单返回父菜单项时移除子菜单的.active类,导致子菜单内无激活项,需要保证此时子菜单内始终至少有一个li带.active类

优化后的实现代码

// 获取父菜单项
const parentMenuItem = $('ul.menu-wrapper').children('li');

// 父菜单项鼠标进入事件
parentMenuItem.on('mouseenter', function() {
    const subMenu = $(this).find('ul.sub-menu').first();
    // 仅在子菜单未激活时执行初始化
    if (!subMenu.hasClass('active')) {
        subMenu.addClass('active');
        // 优先保留之前的激活子项,无则默认选中第一个
        const activeSubItem = subMenu.find('li.active').first();
        if (activeSubItem.length === 0) {
            subMenu.children('li').first().addClass('active');
        }
    }
});

// 子菜单项鼠标进入事件:切换激活状态
$('ul.sub-menu li').on('mouseenter', function() {
    // 移除兄弟项的active类
    $(this).siblings().removeClass('active');
    // 给当前项添加active类
    $(this).addClass('active');
});

// 父菜单项鼠标离开事件:仅完全离开父项区域时移除激活
parentMenuItem.on('mouseleave', function(e) {
    // 检查鼠标是否移动到子菜单内,不是则移除所有激活类
    if (!$(e.relatedTarget).closest('.sub-menu').length) {
        const subMenu = $(this).find('ul.sub-menu').first();
        subMenu.removeClass('active');
        subMenu.find('li.active').removeClass('active');
    }
});

逻辑说明

  1. 父项mouseenter优化:仅在子菜单未激活时执行初始化,同时优先保留之前的激活子项,没有则默认选中第一个,保证返回父项时子菜单有激活项
  2. 子项mouseenter处理:切换激活状态,移除兄弟项的.active,给当前项添加,实现悬停切换
  3. 父项mouseleave优化:通过e.relatedTarget判断鼠标是否移动到子菜单内,只有完全离开父项区域(包括子菜单)时才移除所有激活类,避免鼠标在父项和子菜单之间移动时误移除

内容的提问来源于stack exchange,提问作者Dave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 06:05:23