Изучение нового языка - это непосильная задача, особенно когда вы сталкиваетесь с ошибкой, ищете решения, и все находится в более старом / другом синтаксисе. Это была проблема, с которой я столкнулся, когда пытался использовать метод EventTarget .addEventListener () и получал результаты переполнения стека для обработчиков событий. Прежде чем мы перейдем к одному из них, давайте поговорим о событиях.

События - это действия или события в нашей программе, которым мы можем назначить ответ. Примером этого может быть, когда кто-то нажимает кнопку Нравится на странице в социальной сети, клик будет событием, а увеличение количества лайков для этого сообщения будет ответом, назначенным этому клику. События могут быть чем угодно, от ошибки до загрузки страницы, перетаскивания элемента или выделения текста, если вы хотите, чтобы страница Справка по событиям MDN была расширена в виде списка.

Один из способов получать уведомления о событиях DOM - это обработчики событий. Их обычно называют в зависимости от действия, на которое они реагируют, например. при щелчке будет реагировать на "щелчок". Эта часть кода известна как прослушиватель событий, поскольку он прослушивает «щелчок». Блок кода, который мы напишем после этого, известен как обработчик событий. Он будет запущен, как только мы получим наше событие, что называется регистрацией обработчика события. Хотя обработчики событий и прослушиватели событий технически представляют собой две разные вещи, которые работают вместе, термины обычно используются взаимозаменяемо. Давайте посмотрим на это на примере:

const btn = document.querySelector('button');
btn.onclick = () => console.log('It works');
//This would print 'It works' to the console when the button is clicked

В приведенном выше примере используется обозначение стрелочной функции, чтобы показать, как нажатие на нашу кнопку приводит к отображению на нашей консоли сообщения Это работает. Мы продолжим использовать тот же пример с .addEventListener ().

AddEventListener () принимает два параметра: событие и код, который мы хотим запустить (обработчик событий). В более старых версиях был третий параметр - логическое значение, указывающее, будет ли использоваться захват. Теперь третий параметр является необязательным и был изменен на объект, чтобы он мог включать различные свойства (захват, однократный, пассивный и mozSystemGroup).

Захват или всплытие

Захват событий и всплытие событий - это два способа распространения событий, то есть в каком порядке запускаются события. Поскольку элементы вложены, то, где вы начинаете, имеет значение для работы вашей программы. Захват (также известный как просачивание) проходит от самого внешнего элемента к самому внутреннему, как вы можете видеть на изображении ниже. Пузырьки движутся в противоположном направлении, начиная с самого внутреннего элемента, продвигаясь к самому внешнему элементу. Поскольку третий параметр теперь является необязательным, его значение по умолчанию - false, что означает, что события автоматически запускают фазу восходящей цепочки.

Теперь, когда мы знаем о синтаксисе, давайте посмотрим, как будет выглядеть наш пример, написанный с помощью addEventListener:

const btn = document.querySelector('button');
btn.addEventListener('click', (e) => console.log('It works'));
//This would print 'It works' to the console when the button is clicked

Использование addEventListener требует, чтобы я помнил, в каком порядке идут мои параметры, и много больше пишу, зачем его использовать? Этот метод позволяет использовать несколько прослушивателей событий для одного и того же элемента! Если вы снова попытались использовать .onclick на btn, но на этот раз вы не только хотели, чтобы он был в console.log («Это работает»), но и хотели console.log («Что теперь?»), Только «Что теперь?» будет отображаться.

const btn = document.querySelector('button');
btn.onclick = () => console.log('It works');
btn.onclick = () => console.log('Now what?');
//This would print 'Now what?' to the console when the button is clicked, even though we wanted both 'It works' and 'Now what?'

Это происходит потому, что второе событие перезаписывает значение onclick. Вместо того, чтобы выводить на консоль оба значения, мы остаемся с самым последним. С другой стороны, addEventListener позволяет отображать и то, и другое!

const btn = document.querySelector('button');
btn.addEventListener('click', (e) => console.log('It works'));
btn.addEventListener('click', (e) => console.log('Now what?'));
//This would print 'It works' and 'Now what?' to the console when the button is clicked

Наш пример очень прост, и, конечно же, вы можете просто объединить оба оператора в console.log, чтобы их можно было распечатать. Однако в более сложной ситуации, когда вы хотите, чтобы несколько ответов были связаны с одним событием, было бы проще использовать addEventListener. Говоря о нескольких ответах, допустим, у вас есть форма, вы используете одну и ту же форму для добавления (POST) и обновления (PATCH или PUT) информации. В идеале вы хотите использовать одну и ту же форму для обоих, поскольку вы знаете, что можете добавить несколько addEventListeners к одному элементу. Когда вы обновляете, вам больше не нужен прослушиватель событий для сообщения, вместо его удаления (так как он все еще нужен для других POST), вы можете добавить .removeEventListener ()! Это может быть написано по-разному, в зависимости от вашего кода, но чтобы показать, как это будет работать, я поместил прослушиватели событий в отдельные функции.

const btn = document.querySelector('button');
function pertainingToPost {
   //code
   btn.addEventListener('click', (e) => functionA);
}
//This would continue to functionA when the button is hit in the POST
function pertainingToPatchOrPut {
   //code
   btn.removeEventListener('click', (e) => functionA);
   btn.addEventListener('click', (e) => functionB);
}
//In a PATCH/PUT this would remove the first event listener then continue to functionB when the button is hit

Это позволяет обеим функциям работать так, как мы хотим, и избегать любых возможных осложнений. RemoveEventListener () требует, чтобы первые два параметра были идентичны addEventListener (), который вы хотите удалить. Что касается необязательного третьего параметра, removeEventListener () проверяет только захват / useCapture.

element.addEventListener('click', functionA, { passive: true });

element.removeEventListener('click', functionA, { passive: true });
// Succeeds
element.removeEventListener('click', functionA, { capture: false });
// Succeeds
element.removeEventListener('click', functionA, { capture: true });
// Fails
element.removeEventListener('click', functionA, { passive: false });
// Succeeds
element.removeEventListener('click', functionA, false);
// Succeeds
element.removeEventListener('click', functionA, true);
// Fails

Так как removeEventListener () проверяет на наличие захвата / useCapture только все вызовы прохода removeEventListener, кроме тех, для которых для захвата установлено значение true. Это потому, что наш addEventListener имеет необязательное значение {passive: true}, которое не совпадает с {capture: true} или true в последнем прослушивателе событий. Еще одна вещь, которую следует отметить, если для одного и того же события написано несколько прослушивателей событий, в которых все параметры одинаковы, это не приведет к тому, что прослушиватель событий будет вызываться несколько раз. Это связано с тем, что повторяющиеся экземпляры отбрасываются, поэтому нет необходимости в removeEventListener (). Однако, если они написаны с анонимной функцией в качестве обработчика, они не считаются идентичными и могут вызываться несколько раз.

Существует другой тип событий, называемый встроенным или HTML-обработчиком событий, однако это более старый метод, и он не рекомендуется. Он включает в себя смешивание HTML и JavaScript, поэтому мы не будем вдаваться в подробности. Если вам нужна дополнительная информация, вы можете просмотреть Веб-документ MDN или Учебник по событиям Data Flair.

Хотя есть разные способы обработки событий с помощью JavaScript, я лично предпочитаю использовать addEventListener, поскольку он предлагает большую гибкость. Он позволяет иметь несколько прослушивателей событий для одного и того же элемента, дает контроль над запуском кода (захват или всплытие), работает с элементами DOM (а не только с HTML) и имеет противодействующую часть removeEventListener. Однако, если программа проще, все это не нужно, и достаточно будет события on event.