求助:多Dropdown菜单点击时全部展开,如何实现单次仅展开一个?
解决下拉菜单点击全部展开的问题
问题说明
实现点击触发的下拉菜单,默认隐藏内容,点击按钮显示。但点击单个菜单按钮时所有菜单同时展开,希望每次仅展开一个;同时疑问:JS中用到的show类未在HTML预先添加却能运行,是否需要添加?
原代码
HTML
<div class="hidden"> <button id="myFunction()" class="dropbtn">Title of Section</button> <div id="myDropdown" class="hidden-content"> <div class="article-list"></div> </div> </div>
注:存在多个上述结构,所有下拉容器的ID均为myDropdown
CSS
.dropbtn { padding: 16px; font-size: 16px; border: none; cursor: pointer; width: 100%; font-family: 'Turret Road'; font-size: 35px; font-weight: 600; color: var(--default5); text-align: center; border-radius: 15px; background-image: linear-gradient(var(--defaultAccent1), var(--default3Muted)); box-shadow: var(--default1) 3px 3px 3px 3px; } .dropbtn:hover, .dropbtn:focus { background-image: linear-gradient(var(--defaultAccent1), var(--default1)); } .hidden { position: relative; display: inline-block; } .hidden a:hover { background-image: linear-gradient(var(--defaultAccent1), var(--default1)); } .hidden-content { display: none; position: relative; right: 0; width: 100%; background-color: var(--default3Muted); box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); z-index: 1; border-radius: 15px; } .show { display: block; } .hidden-content a { color: var(--default1); padding: 12px 16px; text-decoration: none; display: block; }
JS
function myFunction() { document.getElementById("myDropdown").classList.toggle("show"); } window.onclick = function(event) { if (!event.target.matches('.dropbtn')) { var dropdowns = document.getElementsByClassName("hidden-content"); var i; for (i = 0; i < dropdowns.length; i++) { var openDropdown = dropdowns[i]; if (openDropdown.classList.contains('show')) { openDropdown.classList.remove('show'); } } } }
错误原因
- ID重复违规:HTML中ID必须唯一,所有下拉容器用同一个
myDropdownID,导致JS无法精准定位单个菜单。 - 按钮事件绑定错误:按钮的
id被错误设置为myFunction(),正确的事件绑定应该使用onclick属性调用函数,而非将ID设为函数名。 - 函数无法关联当前菜单:原
myFunction直接操作固定ID的元素,无法区分点击的按钮所属的下拉容器。
关于show类的疑问
不需要预先在HTML中添加show类。classList.toggle()方法会动态为元素添加/移除该类,只要CSS中定义了.show的样式,动态添加后就能立即生效,完全没问题。
修改后的代码
HTML
<!-- 第一个下拉菜单 --> <div class="dropdown-container"> <button onclick="toggleDropdown(this)" class="dropbtn">Title of Section 1</button> <div class="hidden-content"> <div class="article-list"> <a href="#">选项1</a> <a href="#">选项2</a> </div> </div> </div> <!-- 第二个下拉菜单 --> <div class="dropdown-container"> <button onclick="toggleDropdown(this)" class="dropbtn">Title of Section 2</button> <div class="hidden-content"> <div class="article-list"> <a href="#">选项A</a> <a href="#">选项B</a> </div> </div> </div>
用dropdown-container替换原hidden类(更语义化),按钮通过onclick="toggleDropdown(this)"传递自身元素给函数,无需重复ID
CSS
仅修改容器类名,其余样式保留:
.dropbtn { padding: 16px; font-size: 16px; border: none; cursor: pointer; width: 100%; font-family: 'Turret Road'; font-size: 35px; font-weight: 600; color: var(--default5); text-align: center; border-radius: 15px; background-image: linear-gradient(var(--defaultAccent1), var(--default3Muted)); box-shadow: var(--default1) 3px 3px 3px 3px; } .dropbtn:hover, .dropbtn:focus { background-image: linear-gradient(var(--defaultAccent1), var(--default1)); } /* 替换原.hidden类 */ .dropdown-container { position: relative; display: inline-block; } .dropdown-container a:hover { background-image: linear-gradient(var(--defaultAccent1), var(--default1)); } .hidden-content { display: none; position: relative; right: 0; width: 100%; background-color: var(--default3Muted); box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); z-index: 1; border-radius: 15px; } .show { display: block; } .hidden-content a { color: var(--default1); padding: 12px 16px; text-decoration: none; display: block; }
JS
function toggleDropdown(btn) { // 关闭所有其他已展开的下拉菜单 const allOpenDropdowns = document.querySelectorAll('.hidden-content.show'); allOpenDropdowns.forEach(dropdown => { if (dropdown !== btn.nextElementSibling) { dropdown.classList.remove('show'); } }); // 切换当前点击的下拉菜单的显示状态 btn.nextElementSibling.classList.toggle('show'); } window.onclick = function(event) { if (!event.target.matches('.dropbtn')) { const dropdowns = document.getElementsByClassName('hidden-content'); for (let i = 0; i < dropdowns.length; i++) { const openDropdown = dropdowns[i]; if (openDropdown.classList.contains('show')) { openDropdown.classList.remove('show'); } } } }
函数接收点击的按钮元素,通过nextElementSibling找到对应的下拉容器,先关闭其他展开的菜单,再切换当前菜单的状态
内容的提问来源于stack exchange,提问作者sunnybirdboi
相关产品推荐
相关产品推荐

