Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Введение в события JS: DOM API

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

С точки зрения кода, все действия представлены событиями. Вот некоторые из них:

  • click
  • submit
  • keyup/keydown
  • focus
  • contextmenu
  • mouseover
  • mousedown/mouseup

Детализация событий достаточно высокая, набор текста раскладывается на два события: кнопка зажата и кнопка отпущена. Кроме этого, есть специальное событие keypress, которое позволяет отличать горячие клавиши от нормального ввода.

Любое событие связано с конкретным элементом в DOM. Чтобы добавить новое поведение, нужно найти элемент и добавить колбек в метод addEventListener(), который будет вызван тогда, когда произойдет событие:

<button id="myButton"></button>
const button = document.getElementById('myButton');

// Добавляем обработчик, который вызовется при клике на элементе button
button.addEventListener('click', () => alert('Boom 1!'));

// Добавляем второй обработчик
button.addEventListener('click', () => alert('Boom 2!'));

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

При необходимости, можно удалить обработчик, хотя, на практике, это делается редко:

const button = document.getElementById('myButton');

const handler = () => alert('Boom 1!');
button.addEventListener('click', handler);

// Важно что сюда передается ровно та же самая функция (по ссылке)
button.removeEventListener('click', handler);

События можно вызывать программно. Например, это актуально для фокуса. Представьте, что вы открываете чат в надежде написать туда сообщение, но текст не набирается. Для набора текста нужна фокусировка на поле для ввода. По умолчанию этого не происходит и именно в этом месте мы должны поучаствовать:

const input = document.getElementById('textInput');
// Курсор появляется в поле для ввода
// Попробуйте поменять канал в Slack,
// вы увидите что поле для ввода фокусируется автоматически
input.focus();

Как тестировать

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

  1. Откройте консоль на любом сайте. Где есть нужные элементы, например кнопки или формы
  2. Выберите любой элемент, с которым вы хотите потренироваться. Для простоты можно взять body
  3. Добавьте к нему обработчик
  4. Вызовите событие и вы увидите реакцию
const element = document.body;
element.addEventListener('click', () => console.log('wow!'));
// Теперь можно кликать по любой части сайта
wow!

// Если нужен элемент формы

// Выберет первый встреченный input
const element2 = document.querySelector('input');
// тут вешаем обработчик и выводим на экран все что нужно
element2.addEventListener('keyup', () => console.log('pressed!'));

Таким способом можно тестировать любые события на любых сайтах.

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

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

<div id="myElement">Бум!</div>
const button = document.getElementById('myElement');

button.addEventListener('click', (event) => {
  // Обычный объект
  console.log(event);
  // Координаты точки, в которой произошел клик
  console.log(event.clientX);
  console.log(event.clientY);
});

Каждый клик по кнопке, будет приводить к созданию нового объекта event со своими значениями, соответствующими текущему событию. event — обычный объект, наполненный большим количеством свойств, которые проще всего изучать прямо в браузере. У разных событий есть как общие свойства, так и специфичные, например, у клика есть координаты, а у нажатия клавиши — ее значение. Подробнее о свойствах смотрите в документации.

Общие свойства:

  • event.target — DOM-элемент, на котором произошло событие. Через него проще всего добраться до данных, которые могут понадобиться после события
  • event.type — имя события, например click, keyup и так далее

Для примера посмотрим на задачу валидации вводимого пароля. Будем подсвечивать поле для ввода красной рамкой, если пароль слишком короткий:

See the Pen js_dom_events by Hexlet (@hexlet) on CodePen.

Действие по умолчанию

Для некоторых элементов браузер выполняет действие по умолчанию при срабатывании определенных событий. Например, если повесить обработчик на клик по ссылке, то, выполнив этот клик, мы внезапно перейдем на другую страницу, ту, которая была указана в атрибуте href. Здесь мы видим пример того самого действия по умолчанию, на которое никак не влияет наличие обработчиков. Чтобы отменить это действие, а такое бывает нужно часто, необходимо вызвать метод event.preventDefault() внутри обработчика.

<a href="#" id="myElement">Бум!</a>
const button = document.getElementById('myElement');

button.addEventListener('click', (e) => {
  // Если этого не сделать, то браузер выполнит загрузку новой страницы
  e.preventDefault();
  alert(e.target.textContent);
});

Действиями по умолчанию обладают следующие элементы:

  • Клик по ссылке приводит к переходу на страницу, указанную в href атрибуте
  • Клик на кнопку с типом submit начинает отправку формы на сервер
  • Вращение колесом мышки в textarea передвигает текст, если он не помещается
  • Вызов контекстного меню с помощью правого клика мышки

Конкуренция между событиями

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

Но некоторые события все же берутся в обработку сразу. Это касается тех событий, которые генерируются программно, например focus.

Возникает закономерный вопрос, что происходит со страницей во время выполнения обработчика? И здесь возможны варианты. Если обработчик выполняет некоторый код синхронно, например, занимается вычислениями, то в этот момент блокируется все остальное и страница замирает (говорят "фризится"). Если такое поведение длится слишком долго, то некоторые браузеры зависают, а другие предлагают закрыть вкладку. Отсюда вывод, обработчики должны выполнять свою задачу максимально быстро. А что если задача асинхронная, например, выполняется запрос к серверу? В таком случае все продолжает прекрасно работать, так как HTTP-запросы не блокируют выполнение кода.

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

Частые ошибки

Довольно часто новички путаются в функциях и вместо самой функции передают в обработчик результат вызова функции:

const button = document.getElementById('myElement');
const handler = () => {
  alert('Click!');
};

button.addEventListener('click', handler());

Функция handler() выполняется в момент навешивания обработчика на событие, вместо самой функции будет передан результат вызова handler().


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов для веб-приложений
6 октября 10 месяцев
Иконка программы Fullstack-разработчик
Профессия
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
6 октября 16 месяцев

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и соглашаетесь с «Условиями использования»