#javascript #html #css #menu
Вопрос:
Я пытаюсь закрыть боковую панель, когда нажимаю за ее пределами. Я добавил условие, чтобы закрывать его только в том случае, если он открыт ( nav_active
), но мне чего-то не хватает. Ожидаемое поведение будет заключаться в отображении предупреждения, когда я нажимаю внутри или снаружи красного поля.
редактировать после решения я только что понял, что первый щелчок будет снаружи, поэтому, когда я удалю активный класс, ползунок никогда не будет отображаться
"use strict";
var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');
burger.addEventListener('click', function () {
nav.classList.toggle('nav_active');
});
if (nav.classList.contains("nav_active")) {
window.addEventListener('click', function(e) {
nav.classList.remove('nav_active');
});
}
.nav_home, .nav_links, .nav_buttons, .nav_list {
display: inline-block;
vertical-align: middle;
}
.burger {
width: 2.4rem;
height: 2.4rem;
margin: auto 0;
cursor: pointer;
background: black;
}
.nav_list a:hover {
text-decoration: line-through !important;
}
.nav_links {
display: block;
z-index: 0;
position: absolute;
right: 0rem;
width: 80%;
margin-right: 0.1rem;
border-left: 0.1rem solid;
background: red;
}
.nav_item {
display: block;
}
.nav_list {
display: block;
a {
display: block;
}
span {
display: none;
}
}
.nav_active {
background: blue;
display: inline-block;
}
<header id="header">
<div class="header container">
<div class="nav_links">
<h5 class="nav_list">
<span class="noselect">⁄</span>
</h5>
<div class="nav_buttons">
<h5 class="theme-label"></h5>
</div>
</div>
<div class="burger"></div>
</div>
</header>
Ответ №1:
Ваш второй прослушиватель событий никогда не добавляется, потому что вызов функции at .nav_links
не имеет класса .nav_active
. Поэтому вам нужно переместить if (nav.classList.contains("nav_active"))
внутреннюю функцию обработчика этого прослушивателя.
Рабочий пример:
(для демонстрации я изменил фон на зеленый, когда он активен)
"use strict";
var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');
var navSlide = function() {
burger.addEventListener('click', function() {
nav.classList.toggle('nav_active');
console.log("Clicked on Burger");
});
window.addEventListener('click', function(e) { // i exchanged
if (nav.classList.contains("nav_active")) { // these 2 lines
if (nav.contains(e.target)) {
console.log("Clicked in Box");
}
else {
console.log("Clicked outside Box");
}
} // and
}); // these
};
navSlide();
.nav_home,
.nav_links,
.nav_buttons,
.nav_list {
display: inline-block;
vertical-align: middle;
}
.burger {
width: 2.4rem;
height: 2.4rem;
margin: auto 0;
cursor: pointer;
background: black;
}
.nav_list a:hover {
text-decoration: line-through !important;
}
.nav_links {
display: block;
z-index: 0;
position: absolute;
right: 0rem;
width: 80%;
margin-right: 0.1rem;
border-left: 0.1rem solid;
background: red;
}
.nav_item {
display: block;
}
.nav_list {
display: block;
a {
display: block;
}
span {
display: none;
}
}
.nav_active {
display: inline-block;
background-color: green;
}
<header id="header">
<div class="header container">
<div class="nav_links">
<h5 class="nav_list">
<span class="noselect">⁄</span>
</h5>
<div class="nav_buttons">
<h5 class="theme-label"></h5>
<input class="themeSwitch" type="checkbox" id="switch" name="theme" />
<label class="toggle" for="switch"></label>
<label class="switch" for="switch"></label>
</div>
</div>
<div class="burger"></div>
</div>
</header>
Но я думаю, что когда вы просто хотите переключить меню, вы можете просто обработать все с помощью одного прослушивателя событий (и его обработчика). Таким образом, вам просто нужно обработать два случая: если щелчок был на burger
или снаружи nav
(и гамбургер). Третий случай (последний else
) предназначен только для демонстрации.
Рабочий пример:
(я опустил эту navSlide()
функцию)
"use strict";
var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');
window.addEventListener('click', function(e) {
if (e.target.classList.contains('burger')) {
nav.classList.toggle('nav_active');
console.log("Clicked on Burger");
}
else if (!nav.contains(e.target)) {
nav.classList.remove('nav_active');
console.log("Clicked outside Box");
}
else {
console.log("Clicked in Box");
}
});
.nav_home,
.nav_links,
.nav_buttons,
.nav_list {
display: inline-block;
vertical-align: middle;
}
.burger {
width: 2.4rem;
height: 2.4rem;
margin: auto 0;
cursor: pointer;
background: black;
}
.nav_list a:hover {
text-decoration: line-through !important;
}
.nav_links {
display: block;
z-index: 0;
position: absolute;
right: 0rem;
width: 80%;
margin-right: 0.1rem;
border-left: 0.1rem solid;
background: red;
}
.nav_item {
display: block;
}
.nav_list {
display: block;
a {
display: block;
}
span {
display: none;
}
}
.nav_links.nav_active {
display: inline-block;
background-color: green;
}
<header id="header">
<div class="header container">
<div class="nav_links">
<h5 class="nav_list">
<span class="noselect">⁄</span>
</h5>
<div class="nav_buttons">
<h5 class="theme-label"></h5>
<input class="themeSwitch" type="checkbox" id="switch" name="theme" />
<label class="toggle" for="switch"></label>
<label class="switch" for="switch"></label>
</div>
</div>
<div class="burger"></div>
</div>
</header>
Если вы хотите, чтобы второй прослушиватель событий добавлялся только в том случае, если меню открыто ( nav.classList.contains("nav_active")
), а остальное удалено, вам необходимо вложить его в обработчик первого прослушивателя (анонимная функция). Вы должны определить второй обработчик как отдельную функцию (здесь checkClickLocation()
), потому removeEventListener()
что для его остановки требуется ссылка на функцию (здесь checkClickLocation
) в качестве параметра.
Рабочий пример:
"use strict";
var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');
function checkClickLocation(e) {
if (!nav.contains(e.target)) {
nav.classList.remove('nav_active');
window.removeEventListener('click', checkClickLocation);
console.log("Clicked outside Box");
}
else {
console.log("Clicked in Box");
}
}
burger.addEventListener('click', function(e) {
e.stopPropagation()
nav.classList.toggle('nav_active');
if (nav.classList.contains("nav_active")) {
window.addEventListener('click', checkClickLocation);
}
else {
window.removeEventListener('click', checkClickLocation);
}
console.log("Clicked on Burger");
});
.nav_home,
.nav_links,
.nav_buttons,
.nav_list {
display: inline-block;
vertical-align: middle;
}
.burger {
width: 2.4rem;
height: 2.4rem;
margin: auto 0;
cursor: pointer;
background: black;
}
.nav_list a:hover {
text-decoration: line-through !important;
}
.nav_links {
display: block;
z-index: 0;
position: absolute;
right: 0rem;
width: 80%;
margin-right: 0.1rem;
border-left: 0.1rem solid;
background: red;
}
.nav_item {
display: block;
}
.nav_list {
display: block;
a {
display: block;
}
span {
display: none;
}
}
.nav_active {
display: inline-block;
background-color: green;
}
<header id="header">
<div class="header container">
<div class="nav_links">
<h5 class="nav_list">
<span class="noselect">⁄</span>
</h5>
<div class="nav_buttons">
<h5 class="theme-label"></h5>
<input class="themeSwitch" type="checkbox" id="switch" name="theme" />
<label class="toggle" for="switch"></label>
<label class="switch" for="switch"></label>
</div>
</div>
<div class="burger"></div>
</div>
</header>
Комментарии:
1. Хотел бы знать, зачем помещать
addEventListener
коды в сторону функции, а затем вызывать ее. Мы можем выставить его на улицу без какой-либо функции, я думаю?2. Да, я тоже хотел бы это знать. Может быть, @smugdessert знает…
3. я также хотел бы знать, что
4. единственное, что я хочу спросить, это как у меня может быть
window.addEventListener
триггер только приnav_active
добавлении. Я не хочу всегда проверять, где я нажимаю, если знаю, что ползунок закрыт.5. спасибо, я только что начал изучать JS и ценю вашу помощь
Ответ №2:
Вам просто нужно было переместить код в свой прослушиватель — и я переформатировал способ, которым вы назначаете переменную функции. Наконец, я удалил прослушиватель window
событий на выключателе.
"use strict";
var burger = document.querySelector('.burger');
var nav = document.querySelector('.nav_links');
const navSlide = () => {
burger.addEventListener('click', function(ev) {
nav.classList.toggle('nav_active');
if (nav.classList.contains("nav_active")) {
window.addEventListener('click', captureClick);
console.log("ADDED WINDOW LISTENER")
} else {
// remove the window event listener
window.removeEventListener('click', captureClick);
console.log("REMOVED WINDOW LISTENER")
}
});
};
const captureClick = (e) => {
if (nav.contains(e.target)) {
alert("Clicked in Box");
} else {
alert("Clicked outside Box");
}
}
navSlide();
.nav_home,
.nav_links,
.nav_buttons,
.nav_list {
display: inline-block;
vertical-align: middle;
}
.burger {
width: 2.4rem;
height: 2.4rem;
margin: auto 0;
cursor: pointer;
background: black;
}
.nav_list a:hover {
text-decoration: line-through !important;
}
.nav_links {
display: block;
z-index: 0;
position: absolute;
right: 0rem;
width: 80%;
margin-right: 0.1rem;
border-left: 0.1rem solid;
background: red;
}
.nav_item {
display: block;
}
.nav_list {
display: block;
a {
display: block;
}
span {
display: none;
}
}
.nav_active {
display: inline-block;
}
<header id="header">
<div class="header container">
<div class="nav_links">
<h5 class="nav_list">
<span class="noselect">⁄</span>
</h5>
<div class="nav_buttons">
<h5 class="theme-label"></h5>
<input class="themeSwitch" type="checkbox" id="switch" name="theme" />
<label class="toggle" for="switch"></label>
<label class="switch" for="switch"></label>
</div>
</div>
<div class="burger"></div>
</div>
</header>
Комментарии:
1. Как только вы добавили прослушиватель событий, он останется добавленным даже после того, как список классов переключения удалит
nav_active
класс. таким образом, этот кодwindow.addEventListener('click'
всегда будет оставаться активным. Я думаю, это неправильное решение?2. Отличная мысль и спасибо @RajdeepDebnath — код обновлен