Зарегистрируйтесь для доступа к 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);

Мы можем вызывать события программно. Например, это относится к focus.

Представьте, что вы открываете чат и хотите написать в нем сообщение, но текст не появляется. Вам нужно сфокусироваться на поле ввода, чтобы набрать текст.

По умолчанию этого не происходит, и тут в дело вступаем мы:

const input = document.getElementById('textInput');
// Курсор появляется в поле для ввода
// Попробуйте поменять канал
// В большинстве мессенджеров вы увидите, что поле для ввода фокусируется автоматически
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-запросы не блокируют выполнение кода.

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

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

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

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 300 ₽ в месяц
Разработка фронтенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 25 апреля
профессия
от 9 900 ₽ в месяц
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
16 месяцев
с нуля
Старт 25 апреля
профессия
новый
Автоматизированное тестирование веб-приложений на JavaScript
8 месяцев
c опытом
в разработке
Старт 25 апреля

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

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

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

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