javascript - 如何使下拉菜单正确打开?
问题描述
我在一个页面上有 29 个可点击的下拉菜单。我需要它们在单击时打开,然后在单击另一个或页面上的任何其他位置时关闭。我从 w3schools.com 获得此代码。
现在,此代码将打开页面上的第一个菜单。但是,当我单击另一个菜单时,它将再次打开第一个菜单。我无法打开页面上的任何其他菜单。无论单击什么,唯一会打开的菜单是第一个菜单。
我玩弄了代码,最终能够打开其他菜单,问题是第一个菜单会保持打开状态。例如,我会单击菜单 1,它会打开。当我单击菜单 2 时,它会打开,但菜单 1 也会保持打开状态。这适用于页面上的每个菜单。
我把代码弄乱了,以至于菜单不再起作用,我不得不求助于我开始使用的代码。
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myFunction() {
document.getElementById("myDropdown").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');
}
}
}
}
/* Dropdown Button */
.dropbtn {
background-color: #3498DB;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* Dropdown button on hover & focus */
.dropbtn:hover, .dropbtn:focus {
background-color: #2980B9;
}
/* 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;}
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
</div>
</div>
我需要的是每个菜单都可以被点击。然后,当我单击页面或其他菜单时,第一个菜单将关闭并打开第二个菜单。一次只打开一个菜单。
谢谢!
解决方案
首先,尽可能远离 W3Schools,因为众所周知,W3Schools 提供过时、不完整或完全错误的信息。因此,您代码中的许多技术已经过时,不应使用,例如onXyz
内联事件属性、JavaScript 事件属性和getElementsByClassName()
. Mozilla 开发者网络是众所周知的权威资源。
这里的整体解决方案是使用事件委托并允许事件从它们的原始元素(事件目标)冒泡到处理它们的地方。这允许我们只创建一个事件处理程序,而不是为每个菜单创建一个。然后,无论单击哪个菜单,事件处理函数都会将它们全部折叠,然后展开被单击的菜单。document
请注意,在以下代码中,HTML 中没有 JavaScript,没有元素具有id
属性,并且菜单hide
默认应用了 CSS 类,而不是display:none
在元素 CSS 类中设置。这使我们可以自行删除该类,从而使 CSS 的其余部分保持不变。
不依赖id
s,因此当您添加另一个下拉结构时,它无需更改 JavaScript 即可工作。
// Get all the menus into an array, just once:
let menus = Array.prototype.slice.call(document.querySelectorAll(".dropdown-content"));
let openMenu = null;
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function hideAllMenus() {
// Get all the dropdowns into an array.
menus.forEach(function(dropdown) {
// If the element currently is not hidden
if(!dropdown.classList.contains("hide")){
openMenu = dropdown;
dropdown.classList.add('hide'); // Hide it
}
});
}
// Close the dropdown menu if the user clicks outside of it
document.addEventListener("click", function(event) {
hideAllMenus(); // Hide all the menus
// If the clicked item was a menu
if (event.target.classList.contains('dropbtn')) {
if(event.target.nextElementSibling === openMenu){
event.target.nextElementSibling.classList.add("hide");
openMenu = null;
} else {
// Go to the next element that is a sibling of the one that got clicked (the menu)
// and toggle the use of the `hide` CSS class
event.target.nextElementSibling.classList.remove("hide"); // Show the one that was clicked
openMenu = event.target.nextElementSibling;
}
}
});
/* Dropdown Button */
.dropbtn {
background-color: #3498DB;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
/* Dropdown button on hover & focus */
.dropbtn:hover, .dropbtn:focus {
background-color: #2980B9;
}
/* The container <div> - needed to position the dropdown content */
.dropdown {
position: relative;
display: inline-block;
}
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
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}
/* Add or remove this to hide or show */
.hide {display:none;}
<div class="dropdown">
<button class="dropbtn">Dropdown</button>
<div class="dropdown-content hide">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown</button>
<div class="dropdown-content hide">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Dropdown</button>
<div class="dropdown-content hide">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
</div>
</div>
推荐阅读
- javascript - NetSuite Javascript 错误:org.mozilla.javascript.Undefined@26e0a9d9
- java - 比较大型列表并提取缺失数据
- raku - 如何将 .lines Seq 分配给变量并对其进行迭代?
- admin-on-rest - 如何在 react-admin 中翻译所有资源的字段名称
- c# - 如何将 x-www-form-urlencoded post Message 转换为 JSON post Message?
- r - 使用 dplyr 和 tbrf 滚动几何均值
- mautic - 将 Mautic 退回的电子邮件状态与 SalesForce 同步
- scala - 如何在时间窗口内获取最新值
- c# - IIS 8/Angular2+/C# 上的上传进度错误
- css - 浮动元素背景颜色