Клавиша / esc

.addEventListener()

Учим приложение реагировать на действия пользователя.

Время чтения: меньше 5 мин

Кратко

Скопировано

Добавляет элементу действие, которое будет выполнено после срабатывания события. Например, на клик мышки или нажатие клавиши.

Пример

Скопировано

Найдём первую кнопку на странице и будем выводить сообщение в консоль, когда произошёл клик по этой кнопке.

        
          
          const element = document.querySelector('button')element.addEventListener('click', function (event) {  console.log('Произошло событие', event.type)})
          const element = document.querySelector('button')

element.addEventListener('click', function (event) {
  console.log('Произошло событие', event.type)
})

        
        
          
        
      

Как понять

Скопировано

При вызове функции, в неё передаётся специальный объект (в примере выше — event), который у разных типов событий разный. Например, у событий нажатия клавиши есть код клавиши, а у событий перемещения мыши — координаты.

Функция может быть объявлена ранее:

        
          
          const element = document.querySelector('button')function handleClickFunction(event) {  alert('Именованная функция')}element.addEventListener('click', handleClickFunction)
          const element = document.querySelector('button')

function handleClickFunction(event) {
  alert('Именованная функция')
}
element.addEventListener('click', handleClickFunction)

        
        
          
        
      

А может быть анонимной:

        
          
          element.addEventListener('click', function (event) {  alert('Анонимная функция')})
          element.addEventListener('click', function (event) {
  alert('Анонимная функция')
})

        
        
          
        
      

🤖 Заранее созданные функции обычно используют, когда функция содержит в себе много кода или к ней нужно ссылаться несколько раз. Например, когда нужно отписаться от события позже. Для отписки используется метод элемента Element.removeEventListener().

Альтернативный способ отписки от события можно реализовать с помощью объекта AbortController. Подробнее о нём читайте в разделе «На практике».

Анонимные функции удобно использовать при быстрой разработке или когда обработчик создаётся в одном единственном месте и выносить его в отдельную именованную функцию — дольше, чем писать код самой этой функции. В этом случае очень часто используют короткую, стрелочную запись функции:

        
          
          element.addEventListener('click', (event) => {  alert('Анонимная функция')})
          element.addEventListener('click', (event) => {
  alert('Анонимная функция')
})

        
        
          
        
      

Как пишется

Скопировано

Сигнатура функции выглядит следующим образом:

        
          
          element.addEventListener(eventType, handler, options)
          element.addEventListener(eventType, handler, options)

        
        
          
        
      
  • element — любой HTMLElement на странице.
  • eventType — строка, содержащая название события. Наиболее популярные события 'click', 'change', 'submit', 'keydown', 'keyup', 'mousemove', 'mouseenter', 'mouseleave'.
  • handler — функция, которая будет вызвана, когда событие произойдёт.
  • options/capture — необязательный параметр, который описывает дополнительные свойства для срабатывания события.
    • capture — включает или выключает захват события элементом, на который установлен обработчик. Это значит, что событие сначала сработает на элементе и только потом сработает на всех вложенных элементах. Принимает значение true или false
    • options: { capture: bool, passive: bool, once: bool, signal: AbortSignal } — при передаче объекта аргумент будет распознан как объект настроек, так можно установить больше параметров.
      • passive — значение true означает что внутри handler никогда не будет вызвана функция event.preventDefault(), если функция event.preventDefault() всё-таки вызвана, браузер должен её игнорировать и выводить предупредительное сообщение в консоль.
      • once — включает автоматическую отписку от события после первого срабатывания.
      • signal — передаётся ссылка на объект сигнала AbortSignal, который позволяет отписаться от события.

Ниже приведено несколько вариантов вызова функции с разными параметрами:

        
          
          function handleMouseClick(event) {  console.log('Вы нажали на элемент:', event.target)}window.addEventListener('click', handleMouseClick)window.addEventListener('click', handleMouseClick, true)window.addEventListener('click', handleMouseClick, false)window.addEventListener('click', handleMouseClick, {  passive: true,  capture: false})const abortController = new AbortController()window.addEventListener('click', handleMouseClick, {  signal: abortController.signal})
          function handleMouseClick(event) {
  console.log('Вы нажали на элемент:', event.target)
}

window.addEventListener('click', handleMouseClick)
window.addEventListener('click', handleMouseClick, true)
window.addEventListener('click', handleMouseClick, false)
window.addEventListener('click', handleMouseClick, {
  passive: true,
  capture: false
})

const abortController = new AbortController()

window.addEventListener('click', handleMouseClick, {
  signal: abortController.signal
})

        
        
          
        
      

У объекта event есть специальные методы, такие как preventDefault() и stopPropagation(). Остальные методы практически не используются:

  • preventDefault() позволяет заблокировать стандартное поведение браузера. Например, по клику на ссылке — заблокировать переход по этой ссылке.
  • stopPropagation() позволяет остановить распространение события по DOM-дереву.

На практике

Скопировано

Павел Минеев советует

Скопировано

🛠 Обработка передачи третьего параметра для устаревших браузеров.

Проверим, поддерживает ли браузер объект options. Добавим обработчик события на window, передав ему объект options. В нём поле passive будет менять ранее установленную переменную на true при попытке доступа к объекту. Если браузер проверит содержимое options.passive, он поддерживает данные настройки.

        
          
          let hasPassiveSupport = falsetry {  const options = Object.defineProperty({}, 'passive', {    get() {      hasPassiveSupport = true    },  })  window.addEventListener('test', null, options)} catch (err) {}
          let hasPassiveSupport = false

try {
  const options = Object.defineProperty({}, 'passive', {
    get() {
      hasPassiveSupport = true
    },
  })

  window.addEventListener('test', null, options)
} catch (err) {}

        
        
          
        
      

Далее можем просто проверить, поддерживается ли passive. Если поддерживается, то передаём options, иначе — false.

        
          
          window.addEventListener(  'resize',  function () {    // Обработка события  },  hasPassiveSupport ? { passive: true } : false)
          window.addEventListener(
  'resize',
  function () {
    // Обработка события
  },
  hasPassiveSupport ? { passive: true } : false
)

        
        
          
        
      

В случае, если используете passive и capture одновременно, такую проверку можно не делать. Старый браузер воспримет переданный объект как true и включит capture, а новый обработает оба параметра внутри объекта.

        
          
          window.addEventListener('resize', function () {  // Обработка события}, { passive: true, capture: true })
          window.addEventListener('resize', function () {
  // Обработка события
}, { passive: true, capture: true })

        
        
          
        
      

Дока Дог советует

Скопировано

🛠 Базовая обработка событий клавиатуры.

С помощью событий, можно обрабатывать нажатие клавиш на клавиатуре, когда фокус установлен в поле ввода.
В момент нажатия клавиш будем выводить код клавиши, а по нажатию клавиши Enter добавлять сообщение, которое было введено в поле.

        
          
          <div class="event">Ожидание ввода...</div><input type="text" placeholder="Введите сообщение"><div class="result"></div>
          <div class="event">Ожидание ввода...</div>
<input type="text" placeholder="Введите сообщение">
<div class="result"></div>

        
        
          
        
      

Для этого подпишемся на событие keydown. Каждое нажатие клавиши будет создавать событие 'keydown' и функция будет срабатывать. Внутри функции будем получать код клавиши из свойства key объекта события. Если код клавиши оказался 'Enter', то будем сбрасывать значение в поле ввода и выводить результат.

        
          
          const element = document.querySelector('input')element.addEventListener('keydown', function (event) {  const message = '<code>' + event.key + '</code>'  const value = event.target.value  if (event.key === 'Enter' && value.length > 0) {    const messageElement = document.createElement('div')    messageElement.classList.add('message')    messageElement.innerText = value    document.querySelector('.result').appendChild(messageElement)    event.target.value = ''  }  document.querySelector('.event').innerHTML = message})
          const element = document.querySelector('input')

element.addEventListener('keydown', function (event) {
  const message = '<code>' + event.key + '</code>'
  const value = event.target.value

  if (event.key === 'Enter' && value.length > 0) {
    const messageElement = document.createElement('div')

    messageElement.classList.add('message')
    messageElement.innerText = value
    document.querySelector('.result').appendChild(messageElement)
    event.target.value = ''
  }

  document.querySelector('.event').innerHTML = message
})

        
        
          
        
      
Открыть демо в новой вкладке

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

В этом примере мы заменим стандартное поведение в случае, когда пользователь кликает на ссылку. Чтобы стандартное поведение не сработало, нужно вызывать метод preventDefault у события.

        
          
          <a href="https://yandex.ru" target="_blank">  Ссылка на Яндекс</a><a href="https://yandex.ru" target="_blank" id="custom">  Ссылка с изменённым поведением</a><div id="result"></div>
          <a href="https://yandex.ru" target="_blank">
  Ссылка на Яндекс
</a>
<a href="https://yandex.ru" target="_blank" id="custom">
  Ссылка с изменённым поведением
</a>
<div id="result"></div>

        
        
          
        
      

Подпишемся на событие клика по ссылке и вызовем метод preventDefault. После этого определим собственное поведение элемента. Например, будем выводить сообщение на экран:

        
          
          const linkElement = document.querySelector('#custom')const resultElement = document.querySelector('#result')linkElement.addEventListener('click', function (event) {  event.preventDefault()  resultElement.innerText = 'Вы нажали на ссылку, но ничего не произошло!'  setTimeout(function () {    resultElement.innerText = ''  }, 2500)})
          const linkElement = document.querySelector('#custom')
const resultElement = document.querySelector('#result')

linkElement.addEventListener('click', function (event) {
  event.preventDefault()

  resultElement.innerText = 'Вы нажали на ссылку, но ничего не произошло!'
  setTimeout(function () {
    resultElement.innerText = ''
  }, 2500)
})

        
        
          
        
      
Открыть демо в новой вкладке

Окенчиц Владислав советует

Скопировано

🛠 Базовый пример использования AbortController для отписки от слушателя событий.

По умолчанию в большинстве случаев для отписки стоит использовать removeEventListener. Но, если при подписке была использована анонимная функция, то отписаться от такого слушателя через removeEventListener не получится, так как вторым параметром необходимо передать ссылку на функцию-обработчик.

        
          
          const abortController = new AbortController()const element = document.querySelector('#element1')element.addEventListener('click', () => console.log('Подписка активна'), {  signal: abortController.signal})// Вызываем, когда захотим отписаться:abortController.abort()
          const abortController = new AbortController()
const element = document.querySelector('#element1')

element.addEventListener('click', () => console.log('Подписка активна'), {
  signal: abortController.signal
})

// Вызываем, когда захотим отписаться:
abortController.abort()

        
        
          
        
      

🛠 Отписка сразу от нескольких обработчиков.

AbortController может быть удобнее, чем removeEventListener в случае, если нам нужно отписаться сразу от нескольких обработчиков:

        
          
          const abortController = new AbortController()const element1 = document.querySelector('#element1')const element2 = document.querySelector('#element2')element1.addEventListener('click', () => {  // ...}, {signal: abortController.signal})element2.addEventListener('click', () => {  // ...}, {signal: abortController.signal})// Отписываемся одним вызовом сразу от двух обработчиковabortController.abort()
          const abortController = new AbortController()
const element1 = document.querySelector('#element1')
const element2 = document.querySelector('#element2')

element1.addEventListener('click', () => {
  // ...
}, {signal: abortController.signal})
element2.addEventListener('click', () => {
  // ...
}, {signal: abortController.signal})

// Отписываемся одним вызовом сразу от двух обработчиков
abortController.abort()

        
        
          
        
      

🛠 Вешаем слушатель событий на AbortController.

В случае, если необходимо реализовать логику после отписки, то можно слушать событие abort на AbortSignal:

        
          
          const abortController = new AbortController()const signal = abortController.signalsignal.addEventListener('abort', () => {  console.log('Операция отменена')})
          const abortController = new AbortController()
const signal = abortController.signal

signal.addEventListener('abort', () => {
  console.log('Операция отменена')
})