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

多级菜单事件冒泡逻辑解析及子菜单点击异常隐藏问题求解

问题根因拆解
  • 第一个问题:事件冒泡触发了多层菜单的点击回调
    你的「About」和「Profile」对应的li都有has-submenu类,都绑定了点击事件。点击Profile的时候,事件会先触发Profile绑定的回调,再向上冒泡触发外层About绑定的回调,等于一次点击跑了两次处理逻辑。
  • 第二个问题:错误使用e.target导致两次回调操作了同一个子菜单
    e.target指向的是你实际点击的元素(也就是Profile的a标签),冒泡过程中这个值不会变。
    完整的执行流程是:
    1. 点击Profile的a标签,先触发Profile的li的回调:取到Profile下面的子ul,当前是display:none,所以改成display:block
    2. 事件冒泡到About的li的回调:还是取e.target.parentElement(也就是Profile的li)下面的ul,这时候ul已经是display:block了,所以又改成display:none
      所以最终你看到的就是Profile的子菜单闪了一下又关了,看起来像是直接设成了none。
修复方案

两个修改点二选一即可,都加上更稳妥:

  1. 阻止事件冒泡,避免多层回调同时触发:在点击回调第一行加上e.stopPropagation()
  2. 把e.target替换为e.currentTarget:e.currentTarget指向的是当前正在执行回调的、绑定了事件的元素(也就是对应的.has-submenu的li),不会受冒泡影响。修改后的代码如下:
let menus = document.querySelectorAll(".main-navigation ul li a");
menus.forEach((item) => {
    if (item.parentElement.querySelector("ul")) {
        item.parentElement.classList.add("has-submenu");
    }
});

let submenu = document.querySelectorAll(".has-submenu");
submenu.forEach((item) => {
    item.addEventListener("click", (e) => {
        e.preventDefault();
        // 新增:阻止事件冒泡
        e.stopPropagation();
        // 修改:用currentTarget代替target
        let ul = e.currentTarget.querySelector("ul");
        let cs = window.getComputedStyle(ul).display;
        
        if (cs === "none") {
            ul.style.cssText = "display:block";
        }
        else {
            ul.style.cssText = "display:none";
        }
    });
});

CSS和HTML代码不需要做任何修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 20:54:01