首页 > 解决方案 > 如何使下拉菜单正确打开?

问题描述

我在一个页面上有 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>

我需要的是每个菜单都可以被点击。然后,当我单击页面或其他菜单时,第一个菜单将关闭并打开第二个菜单。一次只打开一个菜单。

谢谢!

标签: javascripthtmldrop-down-menu

解决方案


首先,尽可能远离 W3Schools,因为众所周知,W3Schools 提供过时、不完整或完全错误的信息。因此,您代码中的许多技术已经过时,不应使用,例如onXyz 内联事件属性、JavaScript 事件属性和getElementsByClassName(). Mozilla 开发者网络是众所周知的权威资源。

这里的整体解决方案是使用事件委托并允许事件从它们的原始元素(事件目标冒泡到处理它们的地方。这允许我们只创建一个事件处理程序,而不是为每个菜单创建一个。然后,无论单击哪个菜单,事件处理函数都会将它们全部折叠,然后展开被单击的菜单。document

请注意,在以下代码中,HTML 中没有 JavaScript,没有元素具有id属性,并且菜单hide默认应用了 CSS 类,而不是display:none在元素 CSS 类中设置。这使我们可以自行删除该类,从而使 CSS 的其余部分保持不变。

不依赖ids,因此当您添加另一个下拉结构时,它无需更改 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>


推荐阅读