页面嵌套菜单点击子链接后子菜单消失,如何用JS实现持续显示?
嘿,这个问题我之前做项目时也遇到过,其实核心就是子链接的点击事件冒泡到父元素,触发了父菜单的收起逻辑,用几行JavaScript就能轻松解决。我给你整理了一个完整的、可直接复用的方案:
1. 先确认基础菜单结构(示例)
假设你的菜单HTML是类似这样的嵌套结构:
<ul class="menu"> <li class="menu-item has-children"> <a href="#" class="menu-link">父菜单1</a> <ul class="submenu"> <li class="submenu-item"> <a href="/page1" class="submenu-link">子菜单1-1</a> </li> <li class="submenu-item"> <a href="/page2" class="submenu-link">子菜单1-2</a> </li> </ul> </li> <li class="menu-item has-children"> <a href="#" class="menu-link">父菜单2</a> <ul class="submenu"> <li class="submenu-item"> <a href="/page3" class="submenu-link">子菜单2-1</a> </li> </ul> </li> </ul>
2. 匹配你的CSS逻辑
这部分和你现有的设置一致,子菜单默认隐藏,父菜单激活时显示:
/* 子菜单默认隐藏 */ .submenu { display: none; } /* 父菜单激活时显示子菜单 */ .has-children.is-active .submenu { display: block; } /* 激活链接的高亮样式 */ .menu-link.is-active, .submenu-link.is-active { color: #ff4400; font-weight: bold; /* 可根据需求添加其他样式 */ }
3. 核心JavaScript解决方案
这段代码做了三件关键的事:控制父菜单展开/收起、阻止子链接事件冒泡、管理激活类的状态:
// 获取所有带子菜单的父链接 const parentLinks = document.querySelectorAll('.menu-item.has-children .menu-link'); // 获取所有子菜单链接 const childLinks = document.querySelectorAll('.submenu-link'); // 处理父菜单点击:切换子菜单显示/隐藏 parentLinks.forEach(link => { link.addEventListener('click', function(e) { // 如果父链接是占位的#,阻止默认跳转行为 e.preventDefault(); // 找到当前父菜单的容器 const parentItem = this.closest('.menu-item.has-children'); // 切换父菜单的激活状态,控制子菜单显示 parentItem.classList.toggle('is-active'); // 可选:同时只展开一个父菜单(展开当前的,收起其他的) parentLinks.forEach(otherLink => { const otherItem = otherLink.closest('.menu-item.has-children'); if (otherItem !== parentItem) { otherItem.classList.remove('is-active'); } }); }); }); // 处理子菜单点击:保持子菜单可见 childLinks.forEach(link => { link.addEventListener('click', function(e) { // 核心!阻止事件冒泡到父元素,避免触发父菜单的收起逻辑 e.stopPropagation(); // 移除所有链接的激活状态,避免多个高亮 document.querySelectorAll('.menu-link.is-active, .submenu-link.is-active').forEach(activeLink => { activeLink.classList.remove('is-active'); }); // 给当前点击的子链接添加激活类 this.classList.add('is-active'); // 保险:强制父菜单保持激活状态(防止意外收起) const parentItem = this.closest('.menu-item.has-children'); parentItem.classList.add('is-active'); }); });
关键说明
e.stopPropagation()是解决问题的核心:它阻止了子链接的点击事件向上传递到父菜单元素,这样父菜单的收起逻辑就不会被误触发,子菜单就能一直保持显示。- 如果你的父链接是实际的跳转链接(不是
#),可以去掉e.preventDefault(),或者调整逻辑让点击父链接先展开子菜单,再根据需求处理跳转。 - 如果你不需要“同时只展开一个菜单”的功能,删掉父菜单点击事件里的
parentLinks.forEach(otherLink => {...})这段代码即可。
内容的提问来源于stack exchange,提问作者Jakub89
相关产品推荐
相关产品推荐

