Первоначально опубликовано в моем личном блоге.

События в JavaScript позволяют разработчикам прослушивать изменения в документе и обрабатывать их по мере необходимости. Например, вы можете прослушивать нажатие кнопки, чтобы открыть модальное окно. Другой пример — кнопка «прокрутить вверх», когда пользователь прокручивает страницу до половины.

Эта статья поможет новичкам понять, что такое события в JavaScript и как с ними работать.

Зачем использовать события

Современные веб-сайты стали интерактивными и реактивными. Вместо представления информации или функций сразу, некоторые из них могут быть показаны пользователю в зависимости от выполненного конкретного действия. Пример, упомянутый ранее в статье, иллюстрирует это.

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

Список вариантов использования, в которых события полезны, бесконечен. События — неотъемлемая часть веб-разработки с использованием JavaScript, и важно понимать, как их использовать.

Добавить обработчик событий

Для прослушивания событий можно использовать метод addEventListener. Этот метод доступен для каждого элемента и узла в документе.

addEventListener принимает три параметра: первый параметр — это имя события для прослушивания; второй параметр — функция, обрабатывающая это событие; а третий параметр — необязательный параметр, позволяющий задать больше опций для слушателя.

В большинстве случаев вам нужно использовать только первые два параметра. Вот пример обработки события click на кнопке:

const button = document.querySelector("button");
button.addEventListener("click", function (e) {
    alert("Button clicked");
});

Это извлекает первую кнопку на странице и, когда кнопка нажата, показывает предупреждение.

Может ли событие иметь более одного обработчика?

У одного и того же события может быть много обработчиков. Обработчики запускаются один за другим, когда происходит событие.

Объект события

Как видите, функция, переданная в качестве второго параметра addEventListener, получила аргумент e. Это объект Событие. Этот объект может иметь разные свойства в зависимости от его базового типа. Однако у него есть некоторые общие важные свойства.

Часто используемым свойством объекта Event является свойство target. Это элемент, для которого было вызвано событие. Это может быть полезно, когда у вас есть один и тот же обработчик для более чем одного элемента.

Например:

document.querySelector("input").addEventListener("change", function (e) {
    alert(e.target.value);
});

Этот фрагмент кода добавляет обработчик событий к первому элементу input в событии change. Событие change запускается, когда вы меняете значение ввода, а затем перемещаете фокус с ввода (например, щелкаете что-то еще на странице).

Когда происходит событие change и срабатывает обработчик, значение ввода извлекается с помощью e.target.value и используется в предупреждении.

Предотвратить поведение события по умолчанию

В некоторых случаях вы хотите предотвратить поведение определенных событий по умолчанию. Например, когда на странице щелкают ссылку, вы можете захотеть отобразить подтверждающее сообщение, прежде чем пользователь действительно перейдет на новую страницу.

Чтобы предотвратить поведение события по умолчанию, вы можете использовать метод preventDefault() для объекта Event.

Например:

const a = document.querySelector("a.some-link");
a.addEventListener("click", function (e) {
    e.preventDefault();
    if(confirm("Are you sure?")) {
      window.location.href = e.target.href;
    }
});

Это добавляет обработчик событий к событиям click в ссылке с классом some-link. В обработчике события e.preventDefault() используется для предотвращения поведения по умолчанию при открытии страницы, указанной в атрибуте href.

Затем он показывает пользователю окно подтверждения, и если пользователь нажимает «Да» в окне подтверждения, страница открывается, как и ожидалось.

Запретить другим обработчикам обрабатывать это событие

Как упоминалось ранее, у события может быть более одного обработчика. Однако в некоторых случаях может потребоваться отменить обработку этого события другими событиями. Например, если запрос отправляется на сервер при отправке формы, и вы не хотите, чтобы другие обработчики событий отправки формы отправляли дополнительные запросы.

Есть два метода, которые можно использовать для предотвращения обработки того же события другими обработчиками: stopPropagation и stopImmediatePropagation.

stopPropagation используется для предотвращения обработки события другими обработчиками событий во время фазы всплытия.

Всплывание — это когда у вас есть одно и то же событие как для дочерних, так и для родительских элементов. Событие будет инициировано сначала в дочернем элементе, а затем «булькает» к родительскому элементу.

В этом случае stopPropagation предотвращает запуск события в родительском элементе, если оно вызывается в обработчике дочернего элемента. Однако это не препятствует распространению события на другие обработчики событий.

Чтобы предотвратить обработку события последующими обработчиками, вы можете использовать stopImmediatePropagation.

Например:

const button = document.querySelector("button");

button.addEventListener("click", function (e) {
  e.stopImmediatePropagation();
  alert("Hello!");
});

button.addEventListener("click", function (e) {
  alert("Bye!")
})

Хотя кнопка имеет два обработчика событий, которые прослушивают событие click, будет запущен только первый из них, так как он вызывает функцию stopImmediatePropagation.

Разница между preventDefault, stopPropagation и stopImmediatePropagation

preventDefault только предотвращает поведение события по умолчанию. Однако это не мешает другим обработчикам обрабатывать событие.

stopPropagation и stopImmediatePropagation только предотвращают обработку события другими обработчиками. Однако они не предотвращают поведение события по умолчанию.

Если вы хотите предотвратить обработку события поведением по умолчанию и другими обработчиками, используйте preventDefault либо с stopPropagation, либо с stopImmediatePropagation.

Обработка событий в динамических элементах

Рассмотрим следующий пример:

const buttons = document.querySelectorAll(".btn");

buttons.forEach((btn) => {
  btn.addEventListener("click", function (e) {
    alert("Hello!");
  });
})

//create new button
const button = document.createElement('button');
button.classList.add('btn');
button.textContent = "Bye";
document.body.append(button);

В этом примере вы сначала извлекаете все кнопки, имеющие класс btn. Затем вы перебираете эти кнопки и добавляете прослушиватель событий, который просто показывает предупреждение «Hello» при нажатии кнопки.

Затем вы динамически создаете новую кнопку, добавляете класс btn к этой кнопке и добавляете его в body документа.

Если вы попытаетесь щелкнуть кнопки, которые были добавлены в HTML-код документа или которые были добавлены до добавления прослушивателя событий, предупреждение будет отображаться, как и ожидалось. Однако, если вы нажмете новую кнопку, предупреждение отображаться не будет.

Это связано с тем, что элемент не был частью элементов, полученных с помощью querySelectorAll, поскольку в то время он не существовал.

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

В этом случае вместо того, чтобы добавлять обработчик события непосредственно к каждому элементу отдельно, вы можете добавить обработчик события в body документа и использовать e.target, чтобы проверить, соответствует ли сработавший элемент определенному условию.

Например, вы можете преобразовать предыдущий пример в следующий:

document.body.addEventListener("click", function (e) {
  if (e.target.classList.contains("btn")) {
    alert("Hello!");
  }
})

//create new button
const button = document.createElement('button');
button.classList.add('btn');
button.textContent = "Bye";
document.body.append(button);

Вы добавляете обработчик события click в файле body. В обработчике вы проверяете, имеет ли e.target класс btn, и только в этом случае выполняете необходимое действие.

Теперь при щелчке любого из элементов, имеющих класс btn, созданных динамически или изначально, для них будет запущен обработчик событий.

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

Удалить обработчик событий

В некоторых случаях может потребоваться удалить обработчик событий для элемента. Для этого вы можете использовать метод removeEventListener. Этот метод доступен для каждого элемента и узла в документе.

Этот метод получает те же параметры, что и addEventListener. Важно передать ту же функцию, которую вы передали addEventListener. По этой причине люди обычно определяют функцию отдельно, а затем передают ее addEventListener и removeEventListener.

Например:

const button = document.querySelector("button");

function handleClick (e) {
  alert("Hello");
}

button.addEventListener("click", handleClick);

//some time later
button.removeEventListener("click", handleClick);

Заключение

Эта статья поверхностно описывает события и поможет вам лучше понять их. Чтобы узнать больше о событиях в JavaScript, ознакомьтесь со следующими ресурсами:

  1. Введение в события
  2. Справочник по событию