addEventListener в JavaScript — прослушивание событий
Этот материал объясняет, как с помощью addEventListener() получать и обрабатывать DOM-события в JavaScript: мышинные и клавиатурные события, делегация, управление распространением и параметры addEventListener. Включены практические примеры, методы повышения производительности и контроль ошибок.

Многие веб-приложения полагаются на события для выполнения своих задач. Когда человек взаимодействует с интерфейсом (через мышь, клавиатуру или сенсорный экран), генерация события позволяет программе отреагировать. В этом руководстве вы научитесь слушать события в JavaScript, правильно организовывать обработчики и учитывать аспекты производительности и доступности.
Что такое событийно-ориентированное программирование
Событийно-ориентированное программирование — парадигма, в которой выполнение логики зависит от появления событий. События генерируются взаимодействиями пользователя, системными сигналами или асинхронными операциями. Веб-разработка и JavaScript особенно сильно используют этот подход, потому что браузер предоставляет множество встроенных событий и модель распространения.
Кратко: событие — это уведомление о том, что «что-то случилось»; обработчик (listener) — функция, которая выполняется в ответ на это событие.
Что такое обработчик событий (event listener)
Обработчик событий — это функция, запускаемая при возникновении конкретного события. Обработчик «слушает» элемент и вызывает заранее определённую логику, когда событие происходит. Типичные события: клики мыши, нажатия клавиш, изменение размеров окна, изменение значения поля ввода и т. п.
Как создать обработчик с помощью addEventListener
В DOM можно прослушивать события на любом элементе. У всех объектов, поддерживающих события (window, document, элементы), есть метод addEventListener(), унаследованный от интерфейса EventTarget.
Базовый синтаксис:
element.addEventListener("event", functionToExecute);Где:
- element — любой HTML-элемент (кнопка, абзац и т. п.)
- “event” — строка с именем события
- functionToExecute — ссылка на функцию-обработчик
Создадим простую страницу с несколькими элементами:
Document
Welcome
Hello, welcome to my website.
User Info
HTML выше создаёт страницу и подключает файл app.js, где будут задаваться обработчики событий.
Файл app.js — простой пример
document.querySelector('.btn').addEventListener("click", clickDemo)
function clickDemo(){
console.log("Hi there")
}Этот код находит первый элемент с классом .btn и добавляет обработчик для события “click”. При клике в консоль браузера будет выводиться “Hi there”.
Связанный материал: как использовать селекторы DOM (querySelector, querySelectorAll, getElementById).

Мышинные события
Интерфейс MouseEvent охватывает события, связанные с мышью и указателем. Частые события:
- click
- dblclick
- mousemove
- mouseover
- mouseout
- mouseup
- mousedown
Событие click срабатывает при нажатии и отпускании кнопки мыши над элементом. dblclick — при двух быстрых кликах. Можно назначать несколько обработчиков на один элемент: addEventListener поддерживает множественные подписки для одного и того же события.
Пример: dblclick
document.querySelector('.btn').addEventListener("dblclick", dblclickDemo)
function dblclickDemo(){
alert("This is a demonstration of how to create a double-click event")
}После добавления выше вы получите alert при двойном клике. Поскольку двойной клик по сути содержит два click-события, оба обработчика (click и dblclick) могут быть вызваны в одном действии, если они оба подключены.

Когда мышинные события не подходят
Важно: на мобильных устройствах событийная модель отличается — вместо mousemove/mousedown часто используются touchstart, touchmove, touchend. Для поддержания кросс-платформенного UX используйте Pointer Events (pointerdown/pointerup) или отдельную обработку touch-событий.
Клавиатурные события
Интерфейс KeyboardEvent слушает взаимодействие с клавиатурой. Современная рекомендация — использовать keydown и keyup; событие keypress считается устаревшим.
- keydown срабатывает при нажатии клавиши
- keyup — при отпускании
Лучшее место для привязки — конкретный элемент ввода (input, textarea) или document, если нужно глобальное поведение.
Пример: чтение значения поля
let greetings = document.querySelector('p');
document.querySelector('input').addEventListener("keyup", captureInput)
function captureInput(e){
greetings.innerText = (`Hello ${e.target.value}, welcome to my website.`)
}Этот обработчик обновляет текст абзаца при каждом отпускании клавиши, подставляя текущее значение поля. Параметр e — объект события, у которого есть свойство target, ссылающееся на элемент-источник.

Параметры addEventListener и распространение событий
addEventListener принимает третий необязательный аргумент — options или useCapture. Начиная с современных спецификаций, удобно передавать объект options, в котором есть общие поля:
- capture: true/false — слушать во фазе захвата (capture) или в фазе всплытия (bubble)
- once: true/false — автоматически удалить обработчик после первого вызова
- passive: true/false — указать, что обработчик не будет вызывать preventDefault()
Пример с options:
element.addEventListener('scroll', onScroll, { passive: true })Пассивные обработчики полезны для оптимизации прокрутки: браузер знает, что handler не будет препятствовать стандартному поведению, и может выполнять оптимизации.
Фазы распространения
Событие проходит три основные фазы:
- Захват (capture) — событие идёт сверху вниз от document к целевому элементу
- Целевая фаза — событие достигает целевого элемента
- Всплытие (bubble) — событие идёт вверх к родителям
По умолчанию обработчики работают на этапе всплытия (capture: false). Если нужно вмешаться раньше, используйте capture: true.
Примеры остановки распространения
child.addEventListener('click', function(e) {
e.stopPropagation(); // остановит дальнейшее всплытие
});
parent.addEventListener('click', function(e) {
console.log('Родительский обработчик');
});stopImmediatePropagation() дополнительно предотвращает вызов других обработчиков на том же элементе.
Важно: злоупотребление остановкой распространения делает код сложным для поддержки. Предпочитайте делегирование и ясную архитектуру событий.
Делегация событий (Event Delegation)
Делегация — паттерн, при котором один обработчик на родительском элементе обрабатывает события для множества дочерних элементов. Это экономит ресурсы и упрощает динамическое добавление элементов.
Пример делегации:
const list = document.querySelector('#list');
list.addEventListener('click', (e) => {
const item = e.target.closest('.item');
if (!item) return;
// обработка click для элемента .item
});Делегация эффективна, когда элементы создаются динамически или когда нужно минимизировать число подписок.
Удаление обработчиков и управление памятью
Чтобы убрать обработчик, используйте removeEventListener, передав ту же функцию-референс и те же опции capture:
function handler(e) { /* ... */ }
button.addEventListener('click', handler);
button.removeEventListener('click', handler);Если использовать анонимную функцию в addEventListener, её нельзя будет удалить через removeEventListener, поэтому храните ссылку на функцию, если планируете её снять.
Памятные советы:
- Удаляйте обработчики для тяжёлых элементов при удалении из DOM
- Для одноразовых задач используйте { once: true }
Производительность: throttle, debounce и passive
Частые события (scroll, resize, mousemove) могут генерировать сотни вызовов в секунду. Для них используйте:
- debounce — запускать обработчик спустя задержку после последнего события
- throttle — вызывать обработчик не чаще, чем N раз в секунду
Используйте passive: true для scroll/touch-обработчиков, когда не вызываете preventDefault(), чтобы улучшить отзывчивость на мобильных устройствах.
Доступность и надежность
- Всегда думайте о клавиатурных сценариях: обеспечьте функциональность через клавиатуру (Enter, Space) и управляйте фокусом
- Не полагайтесь только на мышиные события — поддерживайте touch и pointer events
- Для интерактивных контролов используйте semantic HTML (button, a, input) и ARIA, когда нужно
Безопасность и приватность
- В обработчиках событий не храните чувствительные данные в глобальных переменных
- Следите за тем, какие данные отправляете на сервер через события ввода — соблюдайте правила приватности и минимизируйте передачу персональных данных
Когда addEventListener не подходит
- Для простых ссылок лучше использовать стандартную поведение вместо кастомного перехода через событие click
- Для массовых агрегаций событий на сервере (telemetry) разумнее собирать события пакетно, а не отправлять каждый клик отдельно
Мини‑методология: как надёжно внедрять обработчики
- Определите точку привязки: конкретный элемент или контейнер для делегации
- Напишите чистую функцию-обработчик, принимающую event
- Ограничьте частоту вызовов (throttle/debounce) для частых событий
- Добавьте { passive: true } для событий прокрутки/тача, если не вызываете preventDefault
- Тестируйте клавиатуру и мобильные устройства
- Удалите обработчики при уничтожении компонента
Чеклист по ролям
- Разработчик:
- Использовать semantic HTML
- Применять делегацию, если много похожих элементов
- Удалять обработчики при размонтировании
- QA:
- Проверить поведение на клавиатуре и в мобильных браузерах
- Проверить обработку исключений внутри обработчиков
- Специалист по доступности:
- Проверить tab order и aria-атрибуты
- Убедиться, что альтернативные способы навигации работают
Дерево принятия решения (Mermaid)
flowchart TD
A[Нужно ли обрабатывать событие?] --> B{Много похожих элементов?}
B -- Да --> C[Применить делегацию на родителе]
B -- Нет --> D[Привязать обработчик к элементу]
C --> E{Событие частое?}
D --> E
E -- Да --> F[Добавить throttle/debounce]
E -- Нет --> G[Обычный обработчик]
F --> H{Нужно ли preventDefault?}
G --> H
H -- Да --> I[passive: false или по умолчанию]
H -- Нет --> J[passive: true]Краткий словарь терминов
- Событие — уведомление о действии (клик, ввод, прокрутка)
- Обработчик — функция, реагирующая на событие
- target — элемент, на котором произошло событие
- Делегация — один обработчик на родителе для многих детей
- Propagation — распространение события (capture → target → bubble)
Шаблон проверок (Acceptance)
- Обработчик реагирует на заданное событие в целевых браузерах
- Поведение идентично при клавиатуре и мыши, где это нужно
- Нет утечек памяти после удаления элементов
- Частые события ограничены throttle/debounce
- Accessibility: элементы доступны через клавиатуру и имеют подходящие aria-метки
Заключение
addEventListener — базовый и мощный инструмент для работы с событиями в браузере. Понимание фаз распространения, опций (capture, once, passive), делегации и контроля частоты вызовов позволяет писать производительный, надёжный и доступный код. При проектировании событийной логики думайте о переносимости (мобильные устройства), доступности и безопасности данных.
Кратко:
- Используйте делегацию для множества динамических элементов
- Применяйте passive и throttle/debounce для улучшения производительности
- Тестируйте клавиатуру и мобильные устройства
Примечание: используйте removeEventListener с той же ссылкой на функцию и теми же опциями, чтобы корректно отписываться от событий.
Похожие материалы
Лучшие виджеты для iPhone — обзор и инструкция
Темы WordPress: выбор, установка, управление
KVM на Arch Linux: установка и первая виртуальная машина
Эффект Зейгарник для продуктивности
Ремонт ноутбука: диагностика и практические советы