У меня проблема с закрытием меню при использовании события 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");
}
}
"спасибо для ответа. Это действительно работает, но единственное, что, когда вы нажимаете внутри раскрывающегося меню, меню закрывается. Любой возможный путь вокруг этого?"
Согласно запросу 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>
Во-первых, не размножайте прослушивание событий внутри первого события кликов. Во-вторых, вы должны обработать событие щелчка документа, если оно не зависает над элементом меню.
Вот ваш скрипт немного изменен с помощью метода "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
Вы выполнили почти 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");
}
Надежда Решает вашу проблему.
Вы можете использовать event.path(array), чтобы узнать, содержит ли путь ваше меню и останавливает событие.
Для браузеров, не поддерживающих путь, перебирайте родителей до тех пор, пока не достигнете тела или не остановитесь, когда он будет равен цели.
https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath