Обработчики Событий в JS (как работает addEventListener)
В этой статье мы с вами разберемся как правильно использовать обработчики событий (addEventListener) в Javascript на различных элементах DOM дерева страниц. Эти элементы могут включать кнопки, ссылки, изображения и так далее.
Любой DOM элемент запускает событие, когда мы с ним как-то взаимодействуем (кликаем, наводим мышь и др.). Обработчики событий в JS используются для того, чтобы реагировать на эти события.
Обработчики событий можно «вешать» на любые элементы DOM (Data Object Model) дерева, а также глобальные объекты window и document.
Предположим, на нашей странице есть html элемент button с классом «btn»:
Давайте выделим наш элемент button и присвоим его переменной button:
Таким образом, каждый раз после срабатывания события «click» будет запускаться наша коллбэк функция и мы будем получать строку «click» в нашей консоли.
Обработчики событий JS (выносим логику коллбэк функции за пределы метода addEventListener)
Мы также можем вынести нашу коллбэк функцию за пределы метода addEventListener, а внутри обработчика событий просто ссылаться на нее:
Плюс такого подхода заключается в том, что теперь мы легко можем повторно использовать логику нашего обработчика событий для других элементов DOM дерева.
Как снять обработчик события addEventListener с элемента?
Чтобы снять обработчик события с какого-либо элемента, нужно использовать метод removeEventListener. В качестве аргументов нужно указать не только название события («click»), но и название коллбэк функции, которая привязана к элементу.
Метод removeEventListener не сработает, если в качестве коллбэк функции использовать безымянную функцию, так как будет отсутствовать возможность сослаться на нее.
Обработка событий на нескольких DOM элементах
Как использовать обработчик событий addEventListener, когда нам требуется использовать его сразу на нескольких элементах?
Предположим, на нашей странице есть 5 кнопок с классом «btn»:
Подход 1. Используем отдельный addEventListener для каждой кнопки
Подход 2. Делегирование события (Event delegation)
Здесь, основная идея заключается в том, что мы можем ловить события, связанные с дочерними элементами (которых может быть очень много), используя единственный родительский элемент.
Это возможно благодаря механизму, который называется «всплытие» (bubbling) в Javascript, который означает, что если событие срабатывает на каком-то элементе, оно также срабатывает на всех его родительских элементах.
Внутри нашей коллбэк функции у нас есть доступ к объекту «Событие» (Event), внутри которого мы можем использовать свойство target, чтобы получить элемент, на который мы кликнули.
Поднятие в JS (Hoisting в Javascript + 3 примера)
Добавим обработчик события, который срабатывает при нажатии пользователем на кнопку:
Метод addEventListener() присоединяет обработчик события к определенному элементу. При этом новый обработчик события не переписывает уже существующие обработчики событий.
Таким образом, вы можете добавлять сколько угодно обработчиков событий к одному элементу. При этом это могут быть обработчики событий одного типа, например, два события нажатия мышкой.
Вы можете добавлять обработчики событий к любому объекту DOM, а не только к HTML элементам, например, к объекту окна.
Метод addEventListener() позволяет легко контролировать то, как обработчик реагирует на, так называемое, «всплывание» события.
Когда используется метод addEventListener(), JavaScript отделяется от разметки HTML, что улучшает читаемость скрипта и позволяет добавлять обработчики событий даже тогда, когда вы не можете контролировать разметку HTML.
Чтобы удалить обработчик события, нужно воспользоваться методом removeEventListener().
Синтаксис:
элемент.addEventListener(событие, функция, useCapture);
Первый параметр — тип события (например, «click» или «mousedown»).
Второй параметр — функция, которая будет вызываться при возникновении события.
Третий параметр — логическое значение (true/false), определяющее следует ли отправить событие дальше («всплывание») или нужно закрыть это событие. Этот параметр необязателен.
Обратите внимание, что в имени события не используется префикс «on» — «click» вместо «onclick».
В следующем примере при нажатии пользователем на элемент появляется окно с сообщением «Hello World!»:
Также, можно задать и внешнюю «именованную» функцию:
Метод addEventListener() позволяет добавлять несколько обработчиков событий к одному и тому же элементу не переписывая уже существующие обработчики событий:
Также, можно добавлять обработчики событий разных типов:
Добавление обработчика событий к объекту window
Метод addEventListener() позволяет добавлять обработчики событий к любому объекту HTML DOM — HTML элементам, HTML документу, объекту окна (объект window) и другим объектам, поддерживающим события как объект xmlHttpRequest.
В следующем примере добавляется обработчик события, который срабатывает, когда пользователь изменяет размер окна браузера:
Передача параметров
Если необходимо передать параметры, то используйте «анонимную» функцию, которая вызывает специализированную функцию с параметрами:
Всплытие или перехват события?
В HTML DOM существует два способа распространения события — всплытие и перехват.
Распространение события — это последовательность обработки события HTML элементами. Если у вас есть элемент
, вложенный в элемент
, то какой элемент должен обработать событие «click» первым?
При всплытии первым обрабатывает событие самый вложенный элемент, затем его родитель и т.д.: таким образом сначала обрабатывать событие «click» будет элемент
При перехвате все происходит наоборот — сначала событие обрабатывает самый внешний элемент, в нашем случае
Метод addEventListener() позволяет задавать тип распространения события. Это можно сделать при помощи параметра «useCapture«:
addEventListener(событие, функция, useCapture );
По умолчанию этот параметр имеет значение false, что задает всплытие события. Если задать ему значение true, то будет использоваться перехват.
Метод removeEventListener()
Метод removeEventListener() удаляет обработчик события, подключенный методом addEventListener():
Поддержка браузерами
Методы addEventListener() и removeEventListener() в настоящее время поддерживаются всеми основными браузерами.
Однако, IE 8 и более ранних версий, а также Opera 6.0 и более ранних версий не поддерживают методы addEventListener() и removeEventListener(). Тем не менее, для этих версий браузеров можно использовать метод attachEvent() для прикрепления обработчика события и метод detachEvent() для его удаления:
элемент.attachEvent(событие, функция);
элемент.detachEvent(событие, функция);
Метод EventTarget.addEventListener()
Синтаксис
Параметры
Возвращаемое значение
Примечания по использованию
Колбэк обработчика событий
Сама колбэк-функция имеет те же параметры и возвращаемое значение что и метод handleEvent() ; То есть колбэк принимает единственный параметр: объект основанный на Event описывая событие, которое произошло и ничего не возвращая.
Например, колбэк обработчика событий, который может использоваться для обработки fullscreenchange (en-US) и fullscreenerror (en-US) может выглядеть так:
Безопасная проверка поддержки option
В более старых версиях спецификации DOM третьим параметром addEventListener было логическое значение, указывающее, следует ли захватывать событие на этапе погружения. Со временем стало ясно, что необходимо больше вариантов. Вместо добавления дополнительных параметров в функцию (усложняя ситуацию при использовании необязательных значений) третий параметр был изменён на объект, который может содержать различные свойства, определяющие значения параметров для настройки обработчика событий.
Поскольку старые браузеры (а также некоторые не слишком старые браузеры) по-прежнему предполагают, что третий параметр является логическим, возникает необходимость создания своего кода, чтобы разумно обрабатывать этот сценарий. Вы можете сделать это, используя функцию обнаружения для каждого из интересующих вас параметров.
Например, если вы хотите проверить параметр passive :
Для проверки поддержки использования какой-либо опции можно просто добавить геттер для неё, используя код, подобный тому, что показан выше.
Если вы хотите добавить обработчик событий, использующий параметры, о которых идёт речь, вы можете сделать это подобным образом:
Вы можете использовать стороннюю библиотеку, такую как Modernizr или Detect It, чтобы проверить поддержку необходимого свойства.
Примеры
Добавление простого обработчика
Эти примеры демонстрируют как использовать addEventListener() для наблюдения за щелчками мышкой по элементу.
HTML Содержимое
JavaScript Содержимое
Результат
Если вам нужно передать параметры в обработчик, вы можете использовать анонимные функции.
Слушатель события с анонимной функцией
HTML Содержимое
JavaScript Содержимое
Notice that the listener is an anonymous function that encapsulates code that is then, in turn, able to send parameters to the modifyText() function, which is responsible for actually responding to the event.
Результат
Слушатель события со стрелочной функцией
JavaScript
Результат
Примечания
addEventListener — это способ зарегистрировать обработчик события, описанный в документации W3C DOM. Вот список преимуществ его использования:
Добавление обработчика во время обработки события
Если EventListener добавлен к EventTarget во время обработки события, он не будет вызван текущими действиями, но может быть вызван на более поздней стадии обработки события, при восходящей обработке.
Несколько одинаковых обработчиков события
Если зарегистрировано несколько одинаковых EventListener на одном EventTarget с одинаковыми параметрами, дублирующиеся обработчики игнорируются. Так как одинаковые обработчики игнорируются, не требуется удалять их вручную с помощью метода removeEventListener.
Значение this в обработчике
Обычно желательно передавать элемент, на котором сработал обработчик события, например, при использовании обобщённых обработчиков для схожих элементов. При добавлении функции при помощи addEventListener() значение переменной this меняется — заметьте, что значение this передаётся в функцию от вызывающего объекта.
В примере выше значение переменной this внутри modifyText() при вызове событием клика равно таблице ‘t’. Это противоположно поведению, которое возникает, если обработчик добавлен в HTML-разметке:
Значение переменной this внутри modifyText() при вызове событием клика будет равно ссылке на глобальный (window) объект (или undefined при использовании strict mode)
Пример с использованием bind и без него:
Наследство Internet Explorer и attachEvent
Совместимость
Note: useCapture не поддерживается, так как IE 8 не имеет альтернативного метода для этого. Также заметьте, что следующий код только добавляет поддержку IE 8. Также, он работает только при соблюдении стандартов: объявление DOCTYPE страницы обязательно.
Старый способ регистрации обработчиков событий
addEventListener() был добавлен в спецификации DOM 2 Events. До этого обработчики добавлялись следующим образом:
Вопросы памяти
Улучшение производительности прокрутки с помощью passive: true
Введение в браузерные события
Событие – это сигнал от браузера о том, что что-то произошло. Все DOM-узлы подают такие сигналы (хотя события бывают и не только в DOM).
Вот список самых часто используемых DOM-событий, пока просто для ознакомления:
События мыши:
События на элементах управления:
Клавиатурные события:
События документа:
CSS events:
Существует множество других событий. Мы подробно разберём их в последующих главах.
Обработчики событий
Событию можно назначить обработчик, то есть функцию, которая сработает, как только событие произошло.
Именно благодаря обработчикам JavaScript-код может реагировать на действия пользователя.
Есть несколько способов назначить событию обработчик. Сейчас мы их рассмотрим, начиная с самого простого.
Использование атрибута HTML
Атрибут HTML-тега – не самое удобное место для написания большого количества кода, поэтому лучше создать отдельную JavaScript-функцию и вызвать её там.
Следующий пример по клику запускает функцию countRabbits() :
Использование свойства DOM-объекта
К примеру, elem.onclick :
Если обработчик задан через атрибут, то браузер читает HTML-разметку, создаёт новую функцию из содержимого атрибута и записывает в свойство.
Этот способ, по сути, аналогичен предыдущему.
Обработчик всегда хранится в свойстве DOM-объекта, а атрибут – лишь один из способов его инициализации.
Эти два примера кода работают одинаково:
В примере ниже назначение через JavaScript перезапишет обработчик из атрибута:
Кстати, обработчиком можно назначить и уже существующую функцию:
Доступ к элементу через this
Внутри обработчика события this ссылается на текущий элемент, то есть на тот, на котором, как говорят, «висит» (т.е. назначен) обработчик.
В коде ниже button выводит своё содержимое, используя this.innerHTML :
Частые ошибки
Если вы только начинаете работать с событиями, обратите внимание на следующие моменты.
…А вот в разметке, в отличие от свойства, скобки нужны:
Так что разметка генерирует такое свойство:
Используйте именно функции, а не строки.
Назначение обработчика строкой elem.onclick = «alert(1)» также сработает. Это сделано из соображений совместимости, но делать так не рекомендуется.
Не используйте setAttribute для обработчиков.
Такой вызов работать не будет:
Регистр DOM-свойства имеет значение.
addEventListener
Например, одна часть кода хочет при клике на кнопку делать её подсвеченной, а другая – выдавать сообщение.
Мы хотим назначить два обработчика для этого. Но новое DOM-свойство перезапишет предыдущее:
Синтаксис добавления обработчика:
Для удаления обработчика следует использовать removeEventListener :
Для удаления нужно передать именно ту функцию-обработчик которая была назначена.
Вот так не сработает:
Обработчик не будет удалён, т.к. в removeEventListener передана не та же функция, а другая, с одинаковым кодом, но это не важно.
Метод addEventListener позволяет добавлять несколько обработчиков на одно событие одного элемента, например:
Так что addEventListener более универсален. Хотя заметим, что таких событий меньшинство, это скорее исключение, чем правило.
Объект события
Чтобы хорошо обработать событие, могут понадобиться детали того, что произошло. Не просто «клик» или «нажатие клавиши», а также – какие координаты указателя мыши, какая клавиша нажата и так далее.
Когда происходит событие, браузер создаёт объект события, записывает в него детали и передаёт его в качестве аргумента функции-обработчику.
Пример ниже демонстрирует получение координат мыши из объекта события:
Некоторые свойства объекта event :
Есть также и ряд других свойств, в зависимости от типа событий, которые мы разберём в дальнейших главах.
Объект-обработчик: handleEvent
Мы также можем использовать класс для этого:
Метод handleEvent не обязательно должен выполнять всю работу сам. Он может вызывать другие методы, которые заточены под обработку конкретных типов событий, вот так:
Теперь обработка событий разделена по методам, что упрощает поддержку кода.
Итого
Есть три способа назначения обработчиков событий:
HTML-атрибуты используются редко потому, что JavaScript в HTML-теге выглядит немного странно. К тому же много кода там не напишешь.
DOM-свойства вполне можно использовать, но мы не можем назначить больше одного обработчика на один тип события. Во многих случаях с этим ограничением можно мириться.
Не важно, как вы назначаете обработчик – он получает объект события первым аргументом. Этот объект содержит подробности о том, что произошло.
Мы изучим больше о событиях и их типах в следующих главах.
JavaScript | Метод addEventListener()
Вступление
Когда мы говорим о документе, который открыт в браузере, тогда мы можем говорить об объектной модели документа (DOM). Что это значит? Это значит, что каждый элемент HTML-разметки может быть «конвертирован» в объект JavaScript, который будет иметь свой набор свойств (пары «ключ/значение»). Есть ли у элемента родитель, есть ли у элемента дети. Какие атрибуты у элемента, сколько классов у элемента, что находится между открывающим и закрывающим тегами элемента. В этим понятно — есть элемент(HTML, XML), есть объект(JavaScript).
Когда мы говорим о событиях в документе, тогда в игру вступают объекты событий и объекты слушателей событий.
Зачем нужны события? Чтобы фиксировать пользовательское взаимодействие с документом. Пользователь может кликнуть, может потянуть мышкой, зажать комбинацию клавиш на клавиатуре. Ещё события нужны для сетевого взаимодействия, например, когда мы получаем данные с сервера или отправляем их на сервер.
Зачем нужны слушатели событий? Чтобы отлавливать события и принимать какие-то действия или бездействия. Метод addEventListener() позволяет добавлять слушатель событий на любой элемент документа. Его большой плюс в том, что на один элемент мы можем вешать любое количество слушателей событий и при этом писать разную логику для обработки самого события. Например, пользователь может выделить какое-нибудь слово в документе, а мы ему выведем определение этого слова и покрасим все похожие слова в документе к синий цвет.
События отправляются объектам, а объекты могут добавлять слушателей событий для наблюдения за событиями. Смысл в том, что сами «События» и «Слушатели событий» тоже являются объектами.
Объект Event просто называется «» (event). Это позволяет сигнализировать о том, что что-то произошло, например, что изображение завершило загрузку.
«» (potential event target) — null или объект EventTarget.
У события есть связанная «» (target) (потенциальная цель события). Если не указано иное, она не имеет значения (null).
У события есть связанная «» (relatedTarget) (потенциальная цель события). Если не указано иное, она не имеет значения (null).
Объект EventTarget представляет цель, которой может быть отправлено событие, когда что-то произошло.
Каждый объект EventTarget имеет связанный «» (event listener list) (список из нуля или более слушателей событий). Изначально это пустой список.
«» (event listener) может использоваться для наблюдения за конкретным событием и состоит из:
1. type (строка)
2. callback (null или объект EventListener)
3. capture (a boolean, изначально ложный false)
4. passive (a boolean, изначально ложный false)
5. once (a boolean, изначально ложный false)
6. removed (a boolean для бухгалтерских целей, изначально ложный false)
Синтаксис метода addEventListener()
target — это цель события. Это объект из документа(или сам документ), которому будет отправлен объект события.
type — это значение атрибута type у события.
callback — устанавливает обратный вызов, который будет вызываться при отправке события.
options — устанавливает параметры для конкретного слушателя. Для совместимости это может быть логическое значение, и в этом случае метод ведет себя точно так же, как если бы значение было указано в качестве захвата параметров — capture options.
Описание
Метод addEventListener() входит в «Интерфейс EventTarget » стандарта объектной модели документа «DOM«.
Пример № 1 — Вызов addEventListener() с двумя параметрами (минимальный набор для вызова)
Получим элемент H1 в переменную:
Добавляем слушатель события для элемента H1:

Сейчас мы можем добавить ещё один слушатель событий. Предлагаю на этот раз передать в функцию сам объект события и посмотреть из чего он состоит:

Обратите внимание. Мы выполнили сразу две задачи при одном клике на одном элементе h1.
Если сейчас посмотреть на синтаксис метода addEventListener() ещё раз, то:
Пример № 2 — Вызов addEventListener() на всём документе
Очень часто можно встретить запись вида document.addEventListener(). Такая запись означает то, что мы вешаем слушатель события на весь документ.
Добавим к этому документу слушатель событий с такими параметрами:
Мы будем получать в консоль тот элемент, по которому будем кликать:
