Проблемы с закрытием меню с помощью onclick и eventlistener

1

У меня проблема с закрытием меню при использовании события 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");
        }
    }
  • 0
    Является ли меню списком ссылок, которые переходят в другие места? Если это так, то не имеет значения, закрывается ли меню при нажатии на ссылку.
Теги:

4 ответа

0
Лучший ответ

редактировать

"спасибо для ответа. Это действительно работает, но единственное, что, когда вы нажимаете внутри раскрывающегося меню, меню закрывается. Любой возможный путь вокруг этого?"

Согласно запросу OP, демо было изменено следующим образом:

  • Первый <a> nchor .drop-down назначен. .trigger

  • Добавлено условие, что при .trigger щелчке e.target (e.target), он будет переключаться. .active в меню.


.contains()

Используйте .contains() чтобы ссылаться .drop-down теги потомков .drop-down и определить, было ли e.target любое из них ( e.target).


демонстрация

скрипка

Подробности прокомментированы в демонстрации

// 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>
  • 0
    Спасибо за ответ. Это работает, но единственное, что, когда вы нажимаете внутри выпадающего меню, меню закрывается. Любой возможный способ обойти это?
  • 0
    Да, ответ отредактирован, @ Idont1
Показать ещё 2 комментария
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

0

Вы выполнили почти 99%. Вам просто нужно вызвать функцию clickOutSide внутри вашего dropdowntrigger.

    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");
   }

Надежда Решает вашу проблему.

0

Вы можете использовать event.path(array), чтобы узнать, содержит ли путь ваше меню и останавливает событие.

Для браузеров, не поддерживающих путь, перебирайте родителей до тех пор, пока не достигнете тела или не остановитесь, когда он будет равен цели.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню