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

按下右键时子菜单递归展开及Active类错误分配问题排查

箭头键控制嵌套子菜单异常问题的修复方案

开发带嵌套子菜单的Web应用时,实现箭头键功能遇到以下问题:

  • 按下右键(→)会递归展开所有子菜单,而非仅当前激活链接的子菜单
  • 多个链接被错误分配active类

问题根源分析

  1. 多元素批量操作:$('.main-link.active')会选中所有带active类的.main-link元素,当存在多个匹配项时,所有对应子菜单都会被展开。
  2. 选择器逻辑缺陷:原上下键逻辑中find('.main-link')会选中目标<li>下所有嵌套的.main-link,导致切换时多个元素被添加active类,进一步加剧右键的异常行为。
  3. active类唯一性未保障:部分逻辑未先清除全局active类就添加新的,导致多个元素同时拥有该类。

解决方案

  • 严格保证active类的唯一性:任何添加active类的操作前,先移除所有.main-link的active类
  • 限制选择器为单个元素:获取当前激活链接时,使用.first()确保只操作一个元素
  • 优化右键逻辑:展开子菜单后,自动将active类切换到子菜单的第一个.main-link(如果存在)
  • 优化上下键逻辑:使用.find('.main-link').first()确保只选中目标<li>下的第一个可交互项

修改后的完整代码

$(document).ready(function() {
    // 初始化:默认激活第一个菜单链接
    $('.main-link').first().addClass('active');

    $(document).keydown(function(e) {
        // 仅获取第一个激活的链接,避免多元素批量操作
        const activeLink = $('.main-link.active').first();
        if (!activeLink.length) return;

        const submenu = activeLink.next('ul');
        switch (e.which) {
            case 37: // 左箭头:收起当前子菜单,若为子菜单则返回父级
                if (submenu.is(':visible')) {
                    submenu.slideUp();
                } else {
                    const parentLi = activeLink.closest('li.treeview').parent().closest('li');
                    if (parentLi.length) {
                        $('.main-link.active').removeClass('active');
                        parentLi.find('.main-link').first().addClass('active');
                    }
                }
                break;
            case 39: // 右箭头:展开当前子菜单,自动激活第一个子项
                if (submenu.length && !submenu.is(':visible')) {
                    submenu.slideDown();
                    const firstSubLink = submenu.find('.main-link').first();
                    if (firstSubLink.length) {
                        $('.main-link.active').removeClass('active');
                        firstSubLink.addClass('active');
                    }
                }
                break;
            case 38: // 上箭头:切换到上一个同级菜单
                const prevLi = activeLink.parent('li').prev('li');
                if (prevLi.length > 0) {
                    $('.main-link.active').removeClass('active');
                    prevLi.find('.main-link').first().addClass('active');
                }
                break;
            case 40: // 下箭头:切换到下一个同级菜单
                const nextLi = activeLink.parent('li').next('li');
                if (nextLi.length > 0) {
                    $('.main-link.active').removeClass('active');
                    nextLi.find('.main-link').first().addClass('active');
                }
                break;
        }
    });

    $('.sidebar-toggle').click(function () {
        $('body').toggleClass('menu-open');
        $(this).prop('title', $('body').hasClass('menu-open') ? 'Collapse Menu' : 'Expand Menu');
        $('.treeview-menu').slideUp();
    });

    // 菜单点击事件
    $('.main-link').on('click', function (event) {
        const clickedLink = $(this);
        const isActive = clickedLink.hasClass('active');

        // 先清除所有激活状态,保证唯一性
        $('.main-link.active').removeClass('active');

        if (!isActive) {
            clickedLink.addClass('active');
        }

        // 切换当前子菜单,收起其他同级子菜单
        clickedLink.next('ul').slideToggle();
        clickedLink.parent('li').siblings('li').find('ul').slideUp();
    });
});

补充说明

  • 初始化时自动激活第一个.main-link,确保页面加载后有默认导航焦点
  • 左箭头新增返回父级菜单的逻辑,完善键盘导航的交互闭环
  • 所有涉及active类的操作都先全局清除,再给单个元素添加,彻底避免多元素激活的问题
  • 右键展开子菜单后自动激活第一个子项,符合键盘导航的常规使用习惯

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 07:57:05