Короче говоря, у меня addEventListener
внутри addEventListener
. Я слушаю событие click
. Вот пример моего кода:
function toggleElement() {
// function stuff
}
anchor.addEventListener('click', (e) => {
e.preventDefault();
if (!anchorWrapper.classList.contains('active')) {
// do some stuff
window.addEventListener('click', toggleElement, false);
} else {
// do some stuff
window.removeEventListener('click', toggleElement, false);
}
});
Каждый раз, когда нажимается элемент привязки, я назначаю прослушиватель событий окну, который прослушивает щелчки. Я ожидаю, что пользователь щелкнет якорь, который, в свою очередь, НЕ ДОЛЖЕН инициализировать toggleElement
, а просто назначит прослушиватель событий окну. Тогда, по моему мнению (которое оказывается неверным), функция должна инициализироваться только при следующем, втором клике в любом месте окна. Однако он запускается при нажатии на элемент привязки.
Что я не так понимаю? Как я могу предотвратить инициализацию функции toggleElement
, когда пользователь нажимает на элемент привязки, а вместо этого ожидает click
событий в окне?
Разве toggleElement не получает «старое» событие клика? Попробуйте установить нулевой тайм-аут:
setTimeout(function() { window.addEventListener('click', toggleElement, false); });
Принял ответ, который включал e.stopPropagation()
, так как он решил мою проблему гораздо аккуратнее.
Может код быстрее вашего клика? Я думаю, что когда вы щелкаете, назначается прослушиватель событий, но вы все еще «щелкаете», поэтому второй прослушиватель событий также обнаруживает щелчок. Поправьте меня если я ошибаюсь.
Попробуйте поставить e.stopPropagation();
после e.preventDefault();
.
На самом деле, проблема заключается в распространении самого события. Я думаю, что добавление e.stopPropagation()
решает проблему гораздо лучше, чем функция setTimeout
. Итак, я принимаю этот ответ. Спасибо!
Нет проблем, рад, что смог помочь!
Проблема в том, что ваше первое событие распространение через DOM до узла (в вашем случае, окна), к которому вы только что добавили обработчик событий. Поскольку распространение продолжается после выхода из вашего обратного вызова, что означает, что после того, как вы добавили второй обработчик событий, он попадет во второй обработчик событий.
Вы можете избежать этого, используя метод stopPropagation
в своем событии. Вы также можете использовать некоторые другие методы, такие как обещание или тайм-аут нулевой длины, чтобы передать его следующей «задаче» JS в движке, но есть также причины, по которым вы не хотели бы этого делать.
Я создал здесь пример кода, который также имеет дело со случаем, когда вы хотите, чтобы последующие клики внутри кнопки (или что-то еще) также запускали второй обработчик событий. Обратите также внимание, что второй обработчик событий отменяет регистрацию, что немного упрощает эту логику.
let target = document.getElementById("target");
let targetWrapper = document.getElementById("targetWrapper");
function secondFunction() {
console.info("Called second callback");
//alert("Second Function Called");
targetWrapper.removeEventListener('click', secondFunction, false);
targetWrapper.classList.remove("active");
}
target.addEventListener('click', (e) => {
console.info("Called first callback")
e.preventDefault();
if (!targetWrapper.classList.contains("active")){
targetWrapper.addEventListener('click', secondFunction, false);
targetWrapper.classList.add("active");
e.stopPropagation();
}
});
body {
font-size: 20px;
font-family:sans-serif;
}
#targetWrapper {
min-height: 400px;
min-width: 400px;
text-align: center;
background-color: green;
position:relative;
}
#target {
vertical-align: middle;
background-color:blue;
color:red;
padding:50px;
position:absolute;
top:100px;
left:50px;
}
#targetWrapper.active{
outline: 3px solid red;
}
<div id = "targetWrapper">
<a id = "target">
Click me!
</a>
</div>
Дополнительная информация о распространении событий и обработчиках:
Вопрос, на который я ответил ранее о порядке обработки событий
Пример распространения события
Ах, я вижу, что я был избит до удара на этом. Независимо от того; Надеюсь, что мое объяснение все же кому-нибудь пригодится.
Спасибо, решил это и приму ответ через некоторое время. Да, он получает старый щелчок. Я думал, что с
window.addEventListener
будет ожидаться новое событие, отличное от старого клика. Но я был неправ.