Клик срабатывает без ожидаемого клика?

Короче говоря, у меня 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 событий в окне?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
60
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Разве toggleElement не получает «старое» событие клика? Попробуйте установить нулевой тайм-аут:

setTimeout(function() { window.addEventListener('click', toggleElement, false); });

Спасибо, решил это и приму ответ через некоторое время. Да, он получает старый щелчок. Я думал, что с window.addEventListener будет ожидаться новое событие, отличное от старого клика. Но я был неправ.

anon 07.04.2019 15:11

Принял ответ, который включал e.stopPropagation(), так как он решил мою проблему гораздо аккуратнее.

anon 07.04.2019 15:22
Ответ принят как подходящий

Может код быстрее вашего клика? Я думаю, что когда вы щелкаете, назначается прослушиватель событий, но вы все еще «щелкаете», поэтому второй прослушиватель событий также обнаруживает щелчок. Поправьте меня если я ошибаюсь.

Попробуйте поставить e.stopPropagation(); после e.preventDefault();.

На самом деле, проблема заключается в распространении самого события. Я думаю, что добавление e.stopPropagation() решает проблему гораздо лучше, чем функция setTimeout. Итак, я принимаю этот ответ. Спасибо!

anon 07.04.2019 15:22

Нет проблем, рад, что смог помочь!

rombie18 07.04.2019 15:29

Проблема в том, что ваше первое событие распространение через 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>

Дополнительная информация о распространении событий и обработчиках:

События DOM уровня 3

Вопрос, на который я ответил ранее о порядке обработки событий

Пример распространения события

Ах, я вижу, что я был избит до удара на этом. Независимо от того; Надеюсь, что мое объяснение все же кому-нибудь пригодится.

ChrisM 07.04.2019 16:00

Другие вопросы по теме