使用onclick和eventlistener关闭菜单时出现问题

时间:2018-10-14 13:06:10

标签: javascript

使用mouseup事件时,关闭菜单时出现问题。 当您在下拉菜单的外部单击时,我希望菜单关闭,这样可以正常工作。但是,当我单击列表元素本身时,菜单一旦打开就不会消失。我希望菜单在您单击元素外部时以及在单击列表项时都消失。

代码在这里: http://jsfiddle.net/6132jg9m/2/

    var dropDownContent = document.querySelector(".drop-down-content");
    var dropDownTrigger = document.querySelector(".drop-down");

    dropDownTrigger.onclick = function () {
        dropDownTrigger.classList.toggle("active");

        document.addEventListener('mouseup', clickedOutside);
    };

    function clickedOutside(e) {
        if (e.target != dropDownContent &&
            e.target.parentNode != dropDownContent) {
            dropDownTrigger.classList.remove("active");
        }
    }

4 个答案:

答案 0 :(得分:1)

首先,请勿在首次点击事件内增加事件监听。其次,您必须将不单击菜单元素的条件定为要执行的文档单击事件。

这是您的脚本,使用“ matches”方法做了一些修改:

    var dropDownTrigger = document.querySelector(".drop-down");

    dropDownTrigger.addEventListener('click', function() {
        dropDownTrigger.classList.toggle("active");
    });

    document.addEventListener('mouseup', function() {
        if (!dropDownTrigger.matches(':hover')) {
            dropDownTrigger.classList.remove("active");
        }
    });

https://developer.mozilla.org/en-US/docs/Web/API/Element/matches

答案 1 :(得分:0)

您可以使用event.path(数组)查看路径是否包含菜单并停止事件。

对于不支持路径的浏览器,请遍历父级直到到达正文为止,或者在等于目标时停止。

https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath

答案 2 :(得分:0)

您已经完成了将近99%。您只需要在dropdowntrigger中调用clickOutSide函数即可。

    var dropDownContent = document.querySelector(".drop-down-content");
    var dropDownTrigger = document.querySelector(".drop-down");

    dropDownTrigger.onclick = function () {
        dropDownTrigger.classList.toggle("active");
        clickedOutside(e); // this line will solve your problem
    };
    document.addEventListener('mouseup', clickedOutside);

    function clickedOutside(e) {
        if (e.target != dropDownContent &&
            e.target.parentNode != dropDownContent) {
            dropDownTrigger.classList.remove("active");
        }
    }

如果要为菜单项单击添加不同的逻辑,则应编写一个单独的函数。例如

   dropDownTrigger.onclick = function () {
        dropDownTrigger.classList.toggle("active");
        closeMenuDropDown(e); // this line will solve your problem
        document.addEventListener('mouseup', clickedOutside);
   };

   function closeMenuDropDown() {
       dropDownTrigger.classList.remove("active");
   }

希望它可以解决您的问题。

答案 3 :(得分:0)

编辑

  

“答案是正确的。这确实有效,但是唯一的事情是,当您单击下拉菜单内部时,菜单关闭。任何可能的解决方法?”

根据OP的要求,该演示已进行了如下修改:

  • <a>的第一个.drop-down锚分配了.trigger

  • 添加了一个条件,只要单击.triggere.target),它将在菜单上切换.active


.contains()

使用.contains()引用.drop-down后代标记,并确定是否单击了任何后代标记(e.target)。


演示

Fiddle

演示中评论的详细信息

// Register click event on document
document.addEventListener('click', function(e) {

  // Reference the menu (ddn = .drop-down)
  var ddn = document.querySelector('.drop-down');

  /*
  Check if any tag nested in menu (ddn.contains)
  was clicked (e.target)
  */
  var trg = ddn.contains(e.target);

  // if the clicked tag was .trigger...
  if (e.target.matches('.trigger')) {

    // ...toggle .active on menu
    ddn.classList.toggle('active');

    /*
    But if the clicked tag was nested within the menu and the
    menu isn't .active...
    */
  } else if (trg && !ddn.matches('.active')) {

    // ...add the class .active on menu.
    ddn.classList.add('active');

    // Stop event bubbling so it doesn't trigger the ancestor tags
    e.stopPropagation();

    // Or if any descendant tags were clicked and the menu was .active...
  } else if (trg && ddn.matches('.active')) {

    // ...just stop event bubbling 
    e.stopPropagation();

    // Otherwise if it was an ancestor tag of menu...
  } else if (!trg) {

    // ...remove .active from menu
    ddn.classList.remove('active');

  }

});
body {
  margin: 0;
  padding: 0;
  font-size: 1rem;
}

nav>span {
  cursor: pointer;
}

a {
  cursor: pointer;
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
  background: #3ab4a6;
}

ul::after {
  content: "";
  clear: both;
  display: block;
}

nav>ul>li {
  float: left;
  position: relative;
}

a {
  display: block;
  padding: 15px;
  color: #fff;
  text-decoration: none;
  font-size: 1.2rem;
}

a:hover,
.drop-down:hover {
  background: #49505a;
}

.drop-down {
  position: relative;
}

.drop-down.active {
  background: #49505a;
}

.drop-down.active>.drop-down-content {
  display: block;
}

.drop-down.active>a>#arrow {
  transform: rotate(180deg);
}

.drop-down-content {
  display: none;
  position: absolute;
  min-width: 250px;
  background: #49505a;
}

#arrow {
  -webkit-transition: 0.1s;
  transition: 0.1s;
}

.drop-down-content a:hover {
  background: #2f343b;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Drop-down-menu</title>
  <link rel="stylesheet" href="drop-down-menu.css" />
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz" crossorigin="anonymous">

</head>

<body>
  <nav>
    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact us</a></li>
      <li class="drop-down"><a class='trigger'>More <span id="arrow" class="fa fa-angle-down"></span></a>
        <ul class="drop-down-content">
          <li><a>Drop down1</a></li>
          <li><a>Drop down2</a></li>
          <li><a>Drop down3</a></li>
          <li><a>Drop down4</a></li>
        </ul>
      </li>
    </ul>
  </nav>

</body>

</html>