You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 19:29:01