多级菜单用事件委托实现点击展开,核心是监听父容器并用e.target.closest()定位触发按钮,再通过DOM关系找到子菜单,用CSS类控制显隐以支持过渡动画,并可选实现单开模式和嵌套支持。

在多级菜单中用事件委托管理点击展开,核心是把事件监听器绑定到父容器(比如 .menu),利用 event.target 找到真正被点击的菜单项,再根据其状态和结构动态切换子菜单显隐,避免为每个菜单项单独绑定事件。
监听容器,捕获点击目标
不要给每个 <li> 或 <button> 单独加 onclick,而是统一监听最外层菜单容器:
document.querySelector('.menu').addEventListener('click', function(e) {
const trigger = e.target.closest('button[data-toggle="submenu"]');
if (!trigger) return;
// 处理展开/收起逻辑
});
e.target.closest() 能准确匹配最近的触发按钮(即使用户点在图标或文字上),比直接判断 e.target.classList.contains() 更健壮。
识别父子关系与子菜单节点
确保 HTML 结构清晰,例如:
立即学习“Java免费学习笔记(深入)”;
<ul class="menu">
<li>
<button data-toggle="submenu">产品</button>
<ul class="submenu">
<li><a href="#">Web 端</a></li>
<li><a href="#">移动端</a></li>
</ul>
</li>
</ul>
点击按钮后,通过 DOM 关系定位对应子菜单:
- 用
trigger.nextElementSibling(推荐)——要求子菜单紧跟在按钮后 - 或用
trigger.parentElement.querySelector('.submenu')——更灵活,不依赖相邻顺序
切换状态并控制显隐
避免只靠 display: none/block 切换(会破坏过渡动画),建议用 CSS 类控制:
- 默认子菜单加
class="submenu closed",CSS 中设.submenu.closed { max-height: 0; opacity: 0; overflow: hidden; } - 点击时移除
closed类,并用getBoundingClientRect()或scrollHeight动态设置max-height实现平滑展开 - 已展开时,再点一次就加回
closed并重置高度
处理嵌套与关闭其他分支(可选)
若需“单开模式”(点击一个,关闭其他):
- 在展开前,先查找所有已展开的
.submenu:not(.closed),给它们加上closed类 - 注意:只影响同级或全局,避免误关父级已展开的菜单(可根据业务决定是否递归收起上级)
对于深层嵌套(三级、四级),事件委托天然支持——只要结构符合,同一段代码无需修改即可生效。


















