Кратко
Секция статьи "Кратко"Чтобы приложение было интерактивным, нам нужно понимать, что пользователь совершил то или иное действие на странице. Браузер распознает действия пользователя и создаёт событие.
События — это сигналы, которые браузер посылает разработчику, а разработчик может на сигнал реагировать. По аналогии со светофором: видим зелёный свет, едем дальше 🚦
События бывают разных типов: клик, нажатие клавиши на клавиатуре, прокрутка страницы и т.д.
Происходящие события можно обрабатывать и выполнять код, когда нужное событие происходит. Например, при клике на кнопку показывать всплывающее окно.
Как пишется
Секция статьи "Как пишется"Существует два способа обработать события:
- с помощью
on
-свойств DOM-элементов - методом
addEventListener
on
-свойства DOM-элементов
Секция статьи "on-свойства DOM-элементов" Большинство событий связаны с DOM-элементами. Если пользователь кликнул на кнопку, то событие click
связано с конкретным DOM-элементом — кнопкой, на которой кликнул пользователь.
Каждый DOM-элемент имеет большой набор свойств, которые начинаются на on
:
- onclick
- onscroll
- onkeypress
- onmouseenter
- и так далее
Если в это свойство записать анонимную функцию, то эта функция будет вызываться каждый раз, когда браузер будет создавать событие, связанное с этим элементом. Такие функции называют функциями-обработчиками события.
let buttonElement = document.getElementById('change');let squareDiv = document.getElementById('square');// чтобы реагировать на нажатие кнопки, записываем функцию в свойство onclick.// Эта функция будет вызываться при каждом нажатии на кнопку. Часто говорят,// что эта функция обрабатывает событиеbuttonElement.onclick = function() { squareDiv.style= `background-color: ${getColor()};`;}function getColor() { const colors = [ "#49A16C", "#064236", "#ED6742", "#F498AD", "#1A5AD7", "#AFC9DA", "#FFD829", "#282A2E", "#5E6064", "#E6E6E6" ]; return colors[Math.floor(Math.random() * colors.length)];}
let buttonElement = document.getElementById('change'); let squareDiv = document.getElementById('square'); // чтобы реагировать на нажатие кнопки, записываем функцию в свойство onclick. // Эта функция будет вызываться при каждом нажатии на кнопку. Часто говорят, // что эта функция обрабатывает событие buttonElement.onclick = function() { squareDiv.style= `background-color: ${getColor()};`; } function getColor() { const colors = [ "#49A16C", "#064236", "#ED6742", "#F498AD", "#1A5AD7", "#AFC9DA", "#FFD829", "#282A2E", "#5E6064", "#E6E6E6" ]; return colors[Math.floor(Math.random() * colors.length)]; }
Чтобы перестать обрабатывать событие, нужно записать в свойство значение null
.
Метод addEventListener
Секция статьи "Метод addEventListener" 🤖 Если обрабатывать события с помощью on
-свойств, то получится добавить только одну функцию-обработчик на каждый элемент. Часто одного обработчика недостаточно. Чтобы не создавать ограничение на пустом месте, используют альтернативный метод подписки на события — метод addEventListener
.
Метод вызывается у DOM-элемента. Аргументами нужно передать тип события (справочная информация) и функцию, которую нужно выполнить:
let buttonElement = document.getElementById('change');let squareDiv = document.getElementById('square');// чтобы реагировать на нажатие кнопки, подписываемся на событие click и передаем// функцию-обработчик. Эта функция будет вызываться при каждом нажатии на кнопкуbuttonElement.addEventListener('click', function() { squareDiv.style= `background-color: ${getColor()};`;});
let buttonElement = document.getElementById('change'); let squareDiv = document.getElementById('square'); // чтобы реагировать на нажатие кнопки, подписываемся на событие click и передаем // функцию-обработчик. Эта функция будет вызываться при каждом нажатии на кнопку buttonElement.addEventListener('click', function() { squareDiv.style= `background-color: ${getColor()};`; });
Как понять
Секция статьи "Как понять"Функция-обработчик
Секция статьи "Функция-обработчик"Функция-обработчик, или просто обработчик, — это функция, которая вызывается браузером при наступлении события.
При вызове браузер передаёт в обработчик объект события с помощью аргумента.
Объект события — это JavaScript-объект с информацией о событии. В объекте события есть как общие свойства (тип события, время события), так и свойства, которые зависят от типа события (например, на какую кнопку нажал пользователь).
Чтобы работать с объектом события, нужно добавить параметр в объявление обработчика:
// обрабатываем нажатие на кнопки клавиатурыwindow.addEventListener("keydown", function (event) { // используем объект события, чтобы получить информацию о нажатой клавише alert("Вы нажали на кнопку: " + event.key)})
// обрабатываем нажатие на кнопки клавиатуры window.addEventListener("keydown", function (event) { // используем объект события, чтобы получить информацию о нажатой клавише alert("Вы нажали на кнопку: " + event.key) })
Помимо объекта события, внутри функции можно использовать ключевое слово this
. Оно позволяет получить DOM-элемент, на котором сработал обработчик. Это позволяет создать обработчик один раз, но привязать её к нескольким DOM-элементам.
Например, мы объявим обработчик в виде именованной функции и повесим её на нажатие нескольких кнопок. При клике на кнопку будем менять её цвет:
function changeColor() { // меняем цвет кнопки, на которой произошло событие. кнопка доступна с помощью // ключевого слова this this.style = `background-color: ${getColor()};`;};let buttons = document.getElementsByTagName('button');for (let i = 0; i < buttons.length; ++i) { let button = buttons[i]; // к каждой кнопке привязываем обработчик button.addEventListener('click', changeColor); // обратите внимание, что мы не вызываем // функцию changeColor, а только пишем ее имя}
function changeColor() { // меняем цвет кнопки, на которой произошло событие. кнопка доступна с помощью // ключевого слова this this.style = `background-color: ${getColor()};`; }; let buttons = document.getElementsByTagName('button'); for (let i = 0; i < buttons.length; ++i) { let button = buttons[i]; // к каждой кнопке привязываем обработчик button.addEventListener('click', changeColor); // обратите внимание, что мы не вызываем // функцию changeColor, а только пишем ее имя }
Всплытие событий
Секция статьи "Всплытие событий"Рассмотрим пример. У нас есть div
элемент, в который вложено видео. Мы подписались на события click
как на div
, так и на video
. Если событие происходит на div
, то мы меняем его цвет на случайный из списка. Если событие происходит на video
, то мы запускаем видео. Попробуйте кликнуть на коробку:
let container = document.getElementById('container');let video = document.getElementById('cat');// обрабатываем событие click на <div>container.addEventListener('click', function() { const colors = ["#49A16C", "#064236", "#ED6742", "#F498AD", "#1A5AD7", "#AFC9DA", "#FFD829", "#282A2E", "#5E6064"]; let randomColorIndex = Math.floor(Math.random() * colors.length); container.style = `background-color: ${colors[randomColorIndex]}`;});// обрабатываем событие click на видеоvideo.addEventListener('click', function() { this.currentTime = 0; // отматываем видео на начало this.play();})
let container = document.getElementById('container'); let video = document.getElementById('cat'); // обрабатываем событие click на <div> container.addEventListener('click', function() { const colors = ["#49A16C", "#064236", "#ED6742", "#F498AD", "#1A5AD7", "#AFC9DA", "#FFD829", "#282A2E", "#5E6064"]; let randomColorIndex = Math.floor(Math.random() * colors.length); container.style = `background-color: ${colors[randomColorIndex]}`; }); // обрабатываем событие click на видео video.addEventListener('click', function() { this.currentTime = 0; // отматываем видео на начало this.play(); })
🤖 Обрати внимание, что событие срабатывает на обоих элементах — цвет фона меняется и запускается видео. Этому есть объяснение, оно называется всплытие событий (event bubbling).
Когда пользователь совершает действие, браузер ищет самый вложенный элемент, к которому относится событие. Затем это событие передаётся родительскому элементу и так далее до самого корня DOM.
В нашем примере мы кликнули на video
, это самый вложенный элемент. Браузер создал событие и мы обработали его в коде. После этого браузер передаёт событие родителю video
(то есть элементу, который содержит video
) — элементу div
. Мы получаем его и обрабатываем. И он всплывает дальше, пока не дойдёт до body
.
Обработчики сначала срабатывают на самом вложенном элементе, затем на его родителе, затем выше и так далее, вверх по цепочке вложенности.
Кликай по блокам на демо и увидишь, как событие всплывает вверх к родителям:
let active;let counter = 0;// обрабатываем событие click на всех <div>let divs = Array.from(document.querySelectorAll('div')).reverse();for (let i = 0; i < divs.length; ++i) { let isLast = (i + 1 === divs.length); divs[i].addEventListener('click', clickHandlerGenerator(isLast));}function clickHandlerGenerator(isLast = false) { return function() { let me = this; setTimeout(function() { if (active) { active.classList.remove('active'); } me.classList.add('active'); active = me; if (isLast) { setTimeout(function() { active.classList.remove('active'); active = undefined; counter = 0; }, 300); } }, counter * 300); ++counter; }}
let active; let counter = 0; // обрабатываем событие click на всех <div> let divs = Array.from(document.querySelectorAll('div')).reverse(); for (let i = 0; i < divs.length; ++i) { let isLast = (i + 1 === divs.length); divs[i].addEventListener('click', clickHandlerGenerator(isLast)); } function clickHandlerGenerator(isLast = false) { return function() { let me = this; setTimeout(function() { if (active) { active.classList.remove('active'); } me.classList.add('active'); active = me; if (isLast) { setTimeout(function() { active.classList.remove('active'); active = undefined; counter = 0; }, 300); } }, counter * 300); ++counter; } }
Всплытие события можно остановить с помощью метода stopPropagation
у объекта события:
video.addEventListener("click", function (event) { event.stopPropagation() this.currentTime = 0 this.play()})
video.addEventListener("click", function (event) { event.stopPropagation() this.currentTime = 0 this.play() })
На практике
Секция статьи "На практике"🛠 Всегда подписывайся на события с помощью addEventListener
, так ты избежишь доработок, когда потребуется повесить несколько обработчиков на одно и то же событие.
🛠 Если нужно обработать все события определённого типа, вызови метод addEventListener
у объекта window
:
// обрабатываем все клики на страницеwindow.addEventListener("click", function () { alert("clicked")})
// обрабатываем все клики на странице window.addEventListener("click", function () { alert("clicked") })
🛠 Если не используешь объект события в обработчике, то не указывай его в списке параметров обработчика. Вместо function
напиши function
.
🛠 Всплытие событий — важный концепт, попробуй с ним поэкспериментировать.