【问题标题】:Toggle menu if click outside then hide如果单击外部则切换菜单然后隐藏
【发布时间】:2022-09-26 05:10:26
【问题描述】:

我正在尝试创建一个菜单,单击帐户将显示菜单,再次单击将关闭菜单。同样,如果有人在菜单外单击,菜单将关闭。我可以做任何事情,但是如果出现问题,即使我点击菜单中的链接,菜单也会关闭。如果有人在菜单外再次单击帐户按钮,我只想关闭菜单。解决办法是什么?

/* 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 if the user clicks outside of it
window.onclick = function(e) {
  if (!e.target.matches(\'.dropbtn span\')) {
    var myDropdown = document.getElementById(\"myDropdown\");
    if (myDropdown.classList.contains(\'show\')) {
      myDropdown.classList.remove(\'show\');
    }
  }
}
.dropdown {
  float: left;
  overflow: hidden;
}

.dropdown .dropbtn {
  cursor: pointer;
  font-size: 16px;
  border: none;
  outline: none;
  color: white;
  padding: 14px 16px;
  background-color: inherit;
  font-family: inherit;
  margin: 0;
}

.dropdown-content {
  display: none;
  z-index: 9;
  width: 200px;
  top: 72px;
  left: 20px;
  background: #fff;
  position: absolute;
  box-shadow: 0px 0px 13px #0000001a;
  border-radius: 5px;
  padding: 17px;
}

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

.dropdown-content a:hover {
  background-color: #dddddd54;
  border: none;
  border-radius: 5px;
}

.show {
  display: block;
}
<div class=\"right-side-menu\">
  <div class=\"menu-item\" onclick=\"searchFunction()\"><span class=\"icon fa-solid fa-magnifying-glass\"></span></div>
  <div class=\"dropbtn menu-item\" onclick=\"myFunction()\"><span class=\"icon fa-regular fa-user\"><span class=\"font\">Account</span></span>
  </div>
  <div class=\"menu-item\"><a href=\"#\"><span class=\"icon fa-regular fa-arrow-right-to-bracket\">LogIn</span></a></div>
  <div class=\"menu-item\"><a href=\"#\"><span class=\"icon fa-regular fa-pen-to-square\"><span class=\"font\">Write</span></span></a></div>
  <div class=\"dropdown-content\" id=\"myDropdown\">
    <a href=\"#\"><i class=\"rbi rbi-bookmark\"></i>Saved Article</a>
    <a href=\"#\"><i class=\"fa-regular fa-clipboard\"></i>My Article</a>
    <a href=\"#\"><i class=\"fa-regular fa-chart-bar\"></i>My Profile</a>
    <a href=\"#\"><i class=\"red fa-solid fa-arrow-right-from-bracket\"></i>Log Out</a>
  </div>
</div>

    标签: javascript html


    【解决方案1】:

    您可以做的是使用Node.contains() 检查单击的目标是否在您的下拉容器中。

    使用此方法您将遇到的唯一问题是,一旦单击事件冒泡到根元素,事件侦听器将立即删除 show 类。要解决此问题,您需要停止帐户按钮上的单击事件以传播到文档。这可以通过Event.stopPropagation() 方法完成。

    const dropdown = document.querySelector("#myDropdown");
    const dropdownBtn = document.querySelector(".dropbtn");
    
    // Close the dropdown if the user clicks outside of it
    document.addEventListener("click", function (e) {
      if (!dropdown.contains(e.target)) { 
        dropdown.classList.remove("show");
      }
    });
    
    // When the user clicks on the button, 
    // toggle between hiding and showing the dropdown content 
    // without triggering the other event listener
    dropdownBtn.addEventListener("click", function (e) {
      e.stopPropagation()
      dropdown.classList.toggle("show");
    });
    .dropdown {
      float: left;
      overflow: hidden;
    }
    
    .dropdown .dropbtn {
      cursor: pointer;
      font-size: 16px;
      border: none;
      outline: none;
      color: white;
      padding: 14px 16px;
      background-color: inherit;
      font-family: inherit;
      margin: 0;
    }
    
    .dropdown-content {
      display: none;
      z-index: 9;
      width: 200px;
      top: 72px;
      left: 20px;
      background: #fff;
      position: absolute;
      box-shadow: 0px 0px 13px #0000001a;
      border-radius: 5px;
      padding: 17px;
    }
    
    .dropdown-content a {
      float: none;
      color: black;
      padding: 12px 16px;
      text-decoration: none;
      display: block;
      text-align: left;
      border: none;
    }
    
    .dropdown-content a:hover {
      background-color: #dddddd54;
      border: none;
      border-radius: 5px;
    }
    
    .show {
      display: block;
    }
    <div class="right-side-menu">
      <div class="menu-item" onclick="searchFunction()"><span class="icon fa-solid fa-magnifying-glass"></span></div>
      <div class="dropbtn menu-item"><span class="icon fa-regular fa-user"><span class="font">Account</span></span>
      </div>
      <div class="menu-item"><a href="#"><span class="icon fa-regular fa-arrow-right-to-bracket">LogIn</span></a></div>
      <div class="menu-item"><a href="#"><span class="icon fa-regular fa-pen-to-square"><span class="font">Write</span></span></a></div>
      <div class="dropdown-content" id="myDropdown">
        <a href="#"><i class="rbi rbi-bookmark"></i>Saved Article</a>
        <a href="#"><i class="fa-regular fa-clipboard"></i>My Article</a>
        <a href="#"><i class="fa-regular fa-chart-bar"></i>My Profile</a>
        <a href="#"><i class="red fa-solid fa-arrow-right-from-bracket"></i>Log Out</a>
      </div>
    </div>

    不同的方法

    如需创建下拉菜单的更好方法,请查看Kyle's video

    【讨论】:

    • 为了解释起见,我没有包括这个,但是一旦单击按钮,您可能应该将事件侦听器添加到文档中。当下拉菜单关闭时,将其删除。
    【解决方案2】:

    使用Node.contains() API 很容易检查是否有人在元素之外单击。所以,逻辑是,

    var dropdown = document.querySelector("#myDropdown");
    addEventListener("click", function (e) {
      if (!(e.target === dropdown ||  dropdown.contains(e.target))) { // if the target of the click isn't the container nor a descendant of the container
        dropdown.classList.remove("show"); // hide the dropdown
      }
    });
    
    

    【讨论】:

    • 不工作。单击它会立即删除显示类。此外,绝对没有理由检查元素是否被直接单击,因为 .contains 无论如何都会返回 true。例如,document.contains(document) 返回 true。
    猜你喜欢
    • 2014-05-05
    • 2023-03-15
    • 2018-12-04
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-12
    • 2010-11-18
    相关资源
    最近更新 更多