在网页多级导航菜单的开发场景中,用户点击子菜单项后,父级菜单常常会因为默认的交互逻辑自动收起,导致用户需要再次展开才能继续操作其他子项,影响使用体验。我们可以通过JavaScript监听子菜单项的点击事件,在事件触发时向上查找对应的父级UL元素,为其添加用于标识展开状态的Class,就能让父级菜单始终保持在展开状态。

实现核心思路
整个功能的实现可以分为三个核心步骤:
- 给所有子菜单项绑定点击事件监听器,捕获用户的点击操作
- 在点击事件触发时,从当前点击的子菜单项向上遍历DOM树,找到对应的父级UL元素
- 为找到的父级UL元素添加指定的展开状态Class,同时可以根据需求处理其他关联逻辑
基础HTML结构示例
首先我们需要准备一个多级菜单的基础HTML结构,方便后续的功能实现和测试:
<ul class="menu">
<li>
菜单项1
<ul class="sub-menu">
<li class="sub-item">子菜单项1-1</li>
<li class="sub-item">子菜单项1-2</li>
</ul>
</li>
<li>
菜单项2
<ul class="sub-menu">
<li class="sub-item">子菜单项2-1</li>
<li class="sub-item">子菜单项2-2</li>
</ul>
</li>
</ul>
CSS样式准备
我们需要定义两个CSS类,一个用于控制菜单的默认收起状态,一个用于标识菜单的展开状态:
/* 子菜单默认隐藏 */
.sub-menu {
display: none;
}
/* 展开状态的子菜单显示 */
.sub-menu.expanded {
display: block;
}
JavaScript实现代码
接下来编写核心的JavaScript代码,实现点击子菜单项时为父级UL添加Class的功能:
// 获取所有子菜单项元素
const subItems = document.querySelectorAll('.sub-item');
// 遍历子菜单项,绑定点击事件
subItems.forEach(item => {
item.addEventListener('click', function(e) {
// 阻止事件冒泡,避免触发父级元素的点击事件
e.stopPropagation();
// 从当前点击的元素开始向上查找父级UL元素
// closest方法会返回匹配指定选择器的最近祖先元素
const parentUl = this.closest('.sub-menu');
// 如果找到了父级UL元素
if (parentUl) {
// 为父级UL添加expanded类,保持展开状态
parentUl.classList.add('expanded');
// 如果需要同时保证更上层的父级菜单也展开,可以继续向上查找
const upperParentUl = parentUl.parentElement.closest('.sub-menu');
if (upperParentUl) {
upperParentUl.classList.add('expanded');
}
}
});
});
代码逻辑说明
上述代码中使用到了几个关键的DOM操作方法:
querySelectorAll:用于获取页面中所有带有sub-item类的子菜单项元素,返回的是一个NodeList集合addEventListener:为每个子菜单项绑定点击事件,当用户点击时触发对应的回调函数closest:从当前元素开始向上遍历DOM树,返回第一个匹配指定选择器的祖先元素,这里是查找最近的带有sub-menu类的UL元素classList.add:为指定的DOM元素添加CSS类,这里是为父级UL添加expanded类,触发CSS中定义的展开样式
适配更多层级的菜单
如果菜单的层级更多,比如有三层甚至更多子菜单,我们可以修改点击事件的处理逻辑,循环向上查找所有的父级UL元素并添加Class:
const subItems = document.querySelectorAll('.sub-item');
subItems.forEach(item => {
item.addEventListener('click', function(e) {
e.stopPropagation();
// 当前元素
let currentElement = this;
// 循环向上查找所有父级UL
while (currentElement) {
// 如果当前元素是UL且带有sub-menu类
if (currentElement.tagName === 'UL' && currentElement.classList.contains('sub-menu')) {
currentElement.classList.add('expanded');
}
// 向上取父元素
currentElement = currentElement.parentElement;
}
});
});
注意事项
在实际开发中还需要注意几个问题:
- 如果菜单本身有默认的收起展开切换逻辑,需要避免添加Class的操作和原有逻辑冲突,可以在原有逻辑的基础上增加判断,只有点击子菜单项时才执行添加Class的操作
- 如果页面是动态加载的菜单内容,需要使用事件委托的方式绑定点击事件,避免动态添加的子菜单项无法触发事件
- 可以根据需求调整
expanded类的样式,比如添加过渡动画,让菜单展开收起的效果更平滑
事件委托的实现方式示例:将点击事件绑定到最外层的菜单容器,通过判断事件目标是否为子菜单项来触发逻辑,这样动态添加的菜单项也能正常响应点击。
JavaScript父级UL子菜单项添加Class菜单展开修改时间:2026-07-04 05:09:24