如何实现多个嵌套下拉菜单?解决仅显示最后一个的问题
问题描述
我搭建了一个简单网站,展示与妻子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>
问题分析与修复
核心问题
- 定位重叠:三个顶级下拉容器都使用
position: absolute且未设置偏移,导致它们完全重叠,视觉上仅最后一个可见。 - 点击逻辑混乱:
doDropdown函数同时切换所有顶级下拉的显示状态,不符合“点击主按钮展开分类,点击分类展开年份”的预期。 - 事件冒泡干扰:点击分类按钮时,事件会冒泡到窗口触发外部关闭逻辑,导致子下拉无法正常显示。
修改后的完整代码
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
相关产品推荐
相关产品推荐

