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

如何实现多个嵌套下拉菜单?解决仅显示最后一个的问题

问题描述

我搭建了一个简单网站,展示与妻子19年来的每月合照,采用lazy load加载图片,添加anchor links实现年份快速跳转。但19个链接过于繁琐,朋友建议使用dropdown menu优化。我将年份分为2020-2024、2010-2019、2005-2009三个子分类,单独每个分类的下拉功能均可正常工作,但同时启用三个分类时,仅最后一个下拉菜单能正常显示。我仅有少量CSS/JS/HTML开发经验,以下是页面相关代码片段:

原JavaScript代码

/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function doDropdown() {
  /*document.getElementById("myDropdown").classList.toggle("show");*/
  document.getElementById("dropDown2020").classList.toggle("show");
  document.getElementById("dropDown2010").classList.toggle("show");
  document.getElementById("dropDown2000").classList.toggle("show");
}

function showDecade2020() {
  document.getElementById("myDropdown2020").classList.toggle("show");
}

function showDecade2010() {
  document.getElementById("myDropdown2010").classList.toggle("show");
}

function showDecade2000() {
  document.getElementById("myDropdown2000").classList.toggle("show");
}

// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');
      }
    }
  }
}

原CSS代码

/* Dropdown Button */

.dropbtn {
  background-color: white;
  color: black;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
  box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.2);
}


/* Dropdown button on hover & focus */

.dropbtn:hover,
.dropbtn:focus {
  background-color: white;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
}


/* The container <div> - needed to position the dropdown content */

.dropdown {
  position: relative;
  display: inline-block;
}


/* Dropdown Content (Hidden by Default) */

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}


/* Links inside the dropdown */

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}


/* Change color of dropdown links on hover */

.dropdown-content a:hover {
  background-color: #ddd;
}


/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */

.show {
  display: block;
}

原HTML代码

<div class="dropdown">
  <button onclick="doDropdown()" class="dropbtn">Jump to a specific year...</button>
  <div id="dropDown2020" class="dropdown-content">
    <button onclick="showDecade2020()" class="dropbtn">2020-2024</button>
    <div id="myDropdown2020" class="dropdown-content">
      <a href="#2024">2024</a>
      <a href="#2023">2023</a>
      <a href="#2022">2022</a>
      <a href="#2021">2021</a>
      <a href="#2020">2020</a>
    </div>
  </div>
  <div id="dropDown2010" class="dropdown-content">
    <button onclick="showDecade2010()" class="dropbtn">2010-2019</button>
    <div id="myDropdown2010" class="dropdown-content">
      <a href="#2019">2019</a>
      <a href="#2018">2018</a>
      <a href="#2017">2017</a>
      <a href="#2016">2016</a>
      <a href="#2015">2015</a>
      <a href="#2014">2014</a>
      <a href="#2013">2013</a>
      <a href="#2012">2012</a>
      <a href="#2011">2011</a>
      <a href="#2010">2010</a>
    </div>
  </div>
  <div id="dropDown2000" class="dropdown-content">
    <button onclick="showDecade2000()" class="dropbtn">2005-2009</button>
    <div id="myDropdown2000" class="dropdown-content">
      <a href="#2009">2009</a>
      <a href="#2008">2008</a>
      <a href="#2007">2007</a>
      <a href="#2006">2006</a>
      <a href="#2005">2005</a>
    </div>
  </div>
</div>

问题分析与修复

核心问题

  1. 定位重叠:三个顶级下拉容器都使用position: absolute且未设置偏移,导致它们完全重叠,视觉上仅最后一个可见。
  2. 点击逻辑混乱:doDropdown函数同时切换所有顶级下拉的显示状态,不符合“点击主按钮展开分类,点击分类展开年份”的预期。
  3. 事件冒泡干扰:点击分类按钮时,事件会冒泡到窗口触发外部关闭逻辑,导致子下拉无法正常显示。

修改后的完整代码

JavaScript代码

// 切换所有顶级分类下拉的显示/隐藏状态
function toggleMainDropdown() {
  const topDropdowns = document.querySelectorAll('.top-dropdown');
  topDropdowns.forEach(dropdown => dropdown.classList.toggle('show'));
}

// 切换对应年份下拉的显示/隐藏,阻止事件冒泡避免触发外部关闭
function toggleDecadeDropdown(event, targetId) {
  event.stopPropagation();
  document.getElementById(targetId).classList.toggle('show');
}

// 点击外部关闭所有下拉菜单
window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
    const allDropdowns = document.querySelectorAll('.dropdown-content');
    allDropdowns.forEach(dropdown => {
      if (dropdown.classList.contains('show')) {
        dropdown.classList.remove('show');
      }
    });
  }
}

CSS代码

/* Dropdown Button */
.dropbtn {
  background-color: white;
  color: black;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
  box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.2);
  width: 100%;
  text-align: left;
}

/* Dropdown button hover/focus style */
.dropbtn:hover,
.dropbtn:focus {
  background-color: white;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
}

/* Main dropdown container */
.dropdown {
  position: relative;
  display: inline-block;
}

/* Top-level dropdown container: position below main button */
.top-dropdown {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
  top: 100%;
  left: 0;
  margin-top: 2px;
}

/* Sub-year dropdown container: position to the right of category button */
.sub-dropdown {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 2;
  top: 0;
  left: 100%;
  margin-left: 2px;
}

/* Dropdown link styles */
.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

/* Hover effect for dropdown links */
.dropdown-content a:hover {
  background-color: #ddd;
}

/* Show dropdown class */
.show {
  display: block !important;
}

HTML代码

<div class="dropdown">
  <button onclick="toggleMainDropdown()" class="dropbtn">Jump to a specific year...</button>
  
  <div id="dropDown2020" class="top-dropdown dropdown-content">
    <button onclick="toggleDecadeDropdown(event, 'myDropdown2020')" class="dropbtn">2020-2024</button>
    <div id="myDropdown2020" class="sub-dropdown dropdown-content">
      <a href="#2024">2024</a>
      <a href="#2023">2023</a>
      <a href="#2022">2022</a>
      <a href="#2021">2021</a>
      <a href="#2020">2020</a>
    </div>
  </div>
  
  <div id="dropDown2010" class="top-dropdown dropdown-content">
    <button onclick="toggleDecadeDropdown(event, 'myDropdown2010')" class="dropbtn">2010-2019</button>
    <div id="myDropdown2010" class="sub-dropdown dropdown-content">
      <a href="#2019">2019</a>
      <a href="#2018">2018</a>
      <a href="#2017">2017</a>
      <a href="#2016">2016</a>
      <a href="#2015">2015</a>
      <a href="#2014">2014</a>
      <a href="#2013">2013</a>
      <a href="#2012">2012</a>
      <a href="#2011">2011</a>
      <a href="#2010">2010</a>
    </div>
  </div>
  
  <div id="dropDown2000" class="top-dropdown dropdown-content">
    <button onclick="toggleDecadeDropdown(event, 'myDropdown2000')" class="dropbtn">2005-2009</button>
    <div id="myDropdown2000" class="sub-dropdown dropdown-content">
      <a href="#2009">2009</a>
      <a href="#2008">2008</a>
      <a href="#2007">2007</a>
      <a href="#2006">2006</a>
      <a href="#2005">2005</a>
    </div>
  </div>
</div>

关键修改说明

  • 给顶级下拉容器添加top-dropdown类,设置top:100%让它们在主按钮下方依次排列,解决重叠问题。
  • 子年份下拉用sub-dropdown类,设置left:100%让它们在分类按钮右侧弹出,层级更清晰。
  • 优化JS函数,用querySelectorAll批量操作元素,添加event.stopPropagation()防止子下拉被误关闭。
  • 调整按钮宽度为100%,让下拉内容与按钮宽度统一,视觉更协调。

内容的提问来源于stack exchange,提问作者TrojanNemo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 18:23:10