如何让JS代码支持多个同ID/类名的下拉菜单正常运行
问题根因
代码仅第一个下拉生效的核心原因:
- 按照HTML规范,单页面内
id属性必须唯一,你当前多个下拉按钮、子菜单、下拉容器都复用了相同id,getElementById只会匹配页面中第一个对应id的元素,其余元素根本无法绑定事件 - 原有JS逻辑只针对单个元素写死了操作逻辑,没有批量给所有下拉按钮绑定事件,也没有做元素关联,点击时只会固定操作第一个子菜单
修复步骤
1. 调整HTML结构(推荐)
如果可以修改Hugo模板,先删掉所有重复的id,类名可以保留(类名允许重复使用),修正后的导航结构参考:
<nav> <ul> <li class="dropdown"> <a class="dropbtn" href="#" aria-expanded="false">Toggle<span class="drop-icon">▾</span></a> <ul class="sub-menu"> <li><a href="/a/">A</a></li> <li><a href="/b/">B</a></li> <li><a href="/c/">C</a></li> </ul> </li> <li class="dropdown"> <a class="dropbtn" href="#" aria-expanded="false">Dropdown <span class="drop-icon">▾</span></a> <ul class="sub-menu"> <li><a href="/d/">D</a></li> <li><a href="/e/">E</a></li> <li><a href="/f/">F</a></li> </ul> </li> </ul> </nav>
暂时改不了Hugo模板也不影响,下面的JS全部基于类名选择元素,不会受重复id干扰。
2. 替换原有JS代码
新代码会给所有下拉按钮批量绑定事件,点击时只操作当前按钮关联的子菜单,同时保留点击外部关闭菜单的交互,还额外加了下拉互斥逻辑(打开当前下拉时自动关闭其他已打开的下拉),符合常规导航使用习惯:
// 给所有下拉按钮绑定点击事件 document.querySelectorAll('.dropbtn').forEach(btn => { btn.addEventListener('click', function(e) { // 阻止按钮默认跳转行为 e.preventDefault(); // 定位当前按钮所属的下拉容器,找到对应的子菜单 const currentSubmenu = this.closest('.dropdown').querySelector('.sub-menu'); // 先关闭其他已打开的下拉菜单,重置对应按钮的aria状态 document.querySelectorAll('.sub-menu.show').forEach(menu => { if (menu !== currentSubmenu) { menu.classList.remove('show'); menu.closest('.dropdown').querySelector('.dropbtn').setAttribute('aria-expanded', 'false'); } }); // 切换当前子菜单的显示状态 currentSubmenu.classList.toggle('show'); // 同步更新当前按钮的aria-expanded属性 const isExpanded = this.getAttribute('aria-expanded') === 'true'; this.setAttribute('aria-expanded', String(!isExpanded)); }) }) // 点击下拉区域外时关闭所有打开的下拉 window.addEventListener('click', function(event) { // 点击的是下拉内部元素(按钮、子菜单项等)时不触发关闭 if (event.target.closest('.dropdown')) return; // 遍历所有已打开的子菜单,关闭并重置状态 document.querySelectorAll('.sub-menu.show').forEach(openMenu => { openMenu.classList.remove('show'); openMenu.closest('.dropdown').querySelector('.dropbtn').setAttribute('aria-expanded', 'false'); }) })
补充说明
- 所有元素选择都基于类名,完全避开id重复的问题,哪怕Hugo暂时输出重复id也能正常运行
- 用
closest()方法做元素关联,不需要给每个下拉生成唯一id就能精准找到当前按钮对应的子菜单,适配Hugo批量生成菜单的场景 - 修复了原有外部点击关闭的判断bug,原来点击下拉图标、子菜单项时可能误触发关闭,新逻辑不会有这个问题
内容的提问来源于stack exchange,提问作者user18336975
相关产品推荐
相关产品推荐

