基于For Loop的Dropdown Menu:实现点击时自动关闭其他下拉菜单
问题
我用For Loop实现的下拉菜单存在两个问题:
- 点击菜单项后,菜单会保持展开状态直至再次点击
- 点击新菜单项时,其他已展开的下拉菜单无法自动关闭
我尝试使用forEach循环、querySelector和querySelectorAll来解决,但目前未成功。请问如何修改代码,实现点击新菜单项时自动关闭其他下拉菜单?
解决方案
核心逻辑是:点击任意菜单时先关闭所有已展开的菜单,再切换当前菜单状态;同时修复子菜单的绑定逻辑,避免仅操作第一个子菜单的问题。
修改后的完整JavaScript代码
// 选择所有菜单和子标题元素 const menus = document.querySelectorAll('.menu'); const subTitles = document.querySelectorAll('.sub-title'); // 绑定主菜单点击事件 menus.forEach(menu => { const menuContent = menu.querySelector('.item'); menu.addEventListener('click', (e) => { e.stopPropagation(); // 关闭所有其他展开的菜单 menus.forEach(otherMenu => { if (otherMenu !== menu) { const otherContent = otherMenu.querySelector('.item'); otherMenu.classList.remove('darkgrey'); otherContent.classList.remove('show'); // 同步关闭其他菜单的子菜单 const otherSubItem = otherMenu.querySelector('.sub-item'); const otherSubTitle = otherMenu.querySelector('.sub-title'); if (otherSubItem) otherSubItem.classList.remove('present'); if (otherSubTitle) otherSubTitle.classList.remove('clear'); } }); // 切换当前菜单的展开/收起状态 menu.classList.toggle('darkgrey'); menuContent.classList.toggle('show'); }); }); // 绑定子菜单标题点击事件 subTitles.forEach(subTitle => { const subItem = subTitle.nextElementSibling; const parentMenu = subTitle.closest('.menu'); const parentItem = subTitle.closest('.item'); subTitle.addEventListener('click', (e) => { e.stopPropagation(); // 切换子菜单显示状态 subItem.classList.toggle('present'); subTitle.classList.toggle('clear'); // 确保父菜单保持展开 parentMenu.classList.add('darkgrey'); parentItem.classList.add('show'); }); }); // 全局点击事件:点击菜单外区域关闭所有菜单 window.addEventListener('click', () => { menus.forEach(menu => { const menuContent = menu.querySelector('.item'); menu.classList.remove('darkgrey'); menuContent.classList.remove('show'); // 关闭所有子菜单 const subItem = menu.querySelector('.sub-item'); const subTitle = menu.querySelector('.sub-title'); if (subItem) subItem.classList.remove('present'); if (subTitle) subTitle.classList.remove('clear'); }); });
关键优化点
- 用
querySelectorAll替代getElementsByClassName,获取静态元素集合,避免动态集合的索引问题 - 点击菜单时先遍历关闭所有其他菜单,实现菜单互斥展开
- 子菜单事件绑定到每个子标题,通过
closest方法定位父元素,避免硬编码索引导致的仅第一个子菜单生效问题 - 添加
e.stopPropagation()阻止事件冒泡,避免点击菜单/子菜单时触发全局关闭事件
说明
HTML和CSS代码无需修改,保持原有样式结构即可。
内容的提问来源于stack exchange,提问作者Szymon Howorus
相关产品推荐
相关产品推荐

