多级菜单事件冒泡逻辑解析及子菜单点击异常隐藏问题求解
问题根因拆解
- 第一个问题:事件冒泡触发了多层菜单的点击回调
你的「About」和「Profile」对应的li都有has-submenu类,都绑定了点击事件。点击Profile的时候,事件会先触发Profile绑定的回调,再向上冒泡触发外层About绑定的回调,等于一次点击跑了两次处理逻辑。 - 第二个问题:错误使用
e.target导致两次回调操作了同一个子菜单e.target指向的是你实际点击的元素(也就是Profile的a标签),冒泡过程中这个值不会变。
完整的执行流程是:- 点击Profile的a标签,先触发Profile的li的回调:取到Profile下面的子ul,当前是
display:none,所以改成display:block - 事件冒泡到About的li的回调:还是取
e.target.parentElement(也就是Profile的li)下面的ul,这时候ul已经是display:block了,所以又改成display:none
所以最终你看到的就是Profile的子菜单闪了一下又关了,看起来像是直接设成了none。
- 点击Profile的a标签,先触发Profile的li的回调:取到Profile下面的子ul,当前是
修复方案
两个修改点二选一即可,都加上更稳妥:
- 阻止事件冒泡,避免多层回调同时触发:在点击回调第一行加上
e.stopPropagation() - 把
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
相关产品推荐
相关产品推荐

