Модель событий

Модель событий #

Событие — сигнал браузера о действии пользователя или изменении среды (клик, ввод, загрузка, изменение размера). Подписка через addEventListener связывает DOM-узел с функцией-обработчиком. Это базовый механизм кнопок плеера, переключателей виджетов и любых интерактивных элементов JSFlow.


addEventListener #

const playBtn = document.querySelector('.player__play')

function onPlayClick(event) {
  console.log('воспроизведение', event.type)
}

playBtn.addEventListener('click', onPlayClick)

Третий аргумент — опции или boolean useCapture:

document.querySelector('.modal').addEventListener(
  'keydown',
  (event) => {
    if (event.key === 'Escape') closeModal()
  },
  { once: true } // снять после первого срабатывания
)

Полезные опции:

ОпцияЭффект
capture: trueфаза перехвата, до целевого элемента
once: trueавтоматически удалить после вызова
passive: trueне вызывать preventDefault (оптимизация scroll)
signalотписаться через AbortController

Объект Event #

document.querySelector('.checkout-bar').addEventListener('click', (event) => {
  event.type // "click"
  event.target // элемент, на котором сработало событие
  event.currentTarget // элемент, на котором висит listener (часто совпадает)
  event.timeStamp
})

Для UI-кнопок с иконкой target может быть вложенный <svg>, а currentTarget — сама <button>.


preventDefault и stopPropagation #

document.querySelector('#newsletter-form').addEventListener('submit', (event) => {
  event.preventDefault() // не перезагружать страницу
  sendNewsletter(new FormData(event.target))
})

document.querySelector('.track-row a').addEventListener('click', (event) => {
  event.stopPropagation() // не всплывать к родителю со своим обработчиком
})

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


removeEventListener #

Нужна та же ссылка на функцию, что при подписке:

function onResize() {
  reflowDashboard()
}

window.addEventListener('resize', onResize)
window.removeEventListener('resize', onResize)

Анонимные стрелочные функции снять нельзя — именуйте обработчик или используйте { once: true } / AbortController:

const controller = new AbortController()

document.querySelector('.playlist').addEventListener(
  'click',
  handlePlaylistClick,
  { signal: controller.signal }
)

controller.abort() // все listeners с этим signal отписаны

Несколько обработчиков #

На один элемент можно повесить несколько listener’ов одного типа — они вызовутся в порядке регистрации:

const widget = document.querySelector('[data-widget="kpi"]')

widget.addEventListener('click', () => widget.classList.add('is-selected'))
widget.addEventListener('click', () => trackMetric('kpi_click'))

Дублирующая подписка той же функции дважды приведёт к двойному вызову.


Итог #

  • addEventListener(type, handler, options) — стандартная подписка на события.
  • event.target — источник; event.currentTarget — элемент с listener.
  • preventDefault — отмена действия браузера; stopPropagation — остановка всплытия.
  • Для отписки храните именованную функцию или AbortSignal.

См. также #