
本文详解如何通过维护当前激活下拉项索引状态,结合事件委托与 stopPropagation,实现多级下拉菜单的「单开互斥」行为——即点击任一菜单项时,自动收起其余已展开的下拉内容。
本文详解如何通过维护当前激活下拉项索引状态,结合事件委托与 `stoppropagation`,实现多级下拉菜单的「单开互斥」行为——即点击任一菜单项时,自动收起其余已展开的下拉内容。
在构建响应式导航栏时,常见的交互需求是:同一时间仅允许一个下拉菜单处于展开状态。原始代码中,每个 .menu 元素独立绑定 click 事件,仅操作自身对应的 .item,导致多个下拉项可同时显示;而全局 window 点击监听逻辑又因闭包变量 i 的终值问题(循环结束后的 i === menu.length)失效,无法正确关闭对应项。
核心解法在于引入状态管理:使用一个全局变量 openIndex 记录当前展开项的索引(初始为 -1 表示无展开项),并在每次点击主菜单时执行「先关闭旧项、再切换新项」的原子操作。
以下是优化后的完整 JavaScript 实现:
const menu = document.getElementsByClassName('menu');
const menucontent = document.getElementsByClassName('item');
const subTitle = document.getElementsByClassName('sub-title');
const subItem = document.getElementsByClassName('sub-item');
let openIndex = -1; // 跟踪当前展开的下拉菜单索引
for (let i = 0; i <p>✅ <strong>关键改进说明</strong>:</p>
- 使用
e.target.closest(selector)替代多个matches()判断,语义更清晰、兼容性更好; -
e.stopPropagation()精准拦截子菜单点击向父.menu的冒泡,避免折叠冲突; -
openIndex在每次主菜单点击后实时更新,确保状态一致性; - 全局 window 监听器中增加
closest()安全校验,防止误判嵌套元素点击。
⚠️ 注意事项:
- HTML 结构需严格保持
.menu → .item、.sub-title → .sub-item的层级关系; - CSS 中
.item.show样式必须定义display: flex(或block),否则classList.toggle('show')无效; - 若后续扩展为动态渲染菜单,建议改用事件委托 +
dataset标识,避免重复绑定。
该方案轻量、可靠,无需依赖框架,适用于任何基于原生 DOM 的多级下拉菜单场景。










