Пошук уроків, статей та іншого контенту
Розберете, що таке події браузера, як вони виникають і які об’єкти можуть бути їхніми джерелами.
Подія — це повідомлення про те, що в браузері щось сталося.
Наприклад:
користувач натиснув кнопку;
увів текст у поле;
навів курсор на елемент;
прокрутив сторінку;
сторінка завантажилася;
таймер завершив відлік;
скрипт сам створив і запустив подію.
JavaScript може підписатися на подію та виконати певну функцію у відповідь на неї. Таку функцію називають обробником події.
Наприклад, кнопка може повідомити про натискання, а JavaScript — змінити текст на сторінці:
<button id="helloButton">Привітатися</button>
<p id="message"></p>
<script>
const button = document.querySelector('#helloButton');
const message = document.querySelector('#message');
button.addEventListener('click', function () {
message.textContent = 'Привіт!';
});
</script>У цьому прикладі:
button — елемент, який може отримати подію.
'click' — назва події.
function () { ... } — обробник події.
addEventListener — метод, який підписує об’єкт на подію.
Події можуть виникати з різних причин.
Найчастіше події спричиняє користувач:
click — натискання;
dblclick — подвійне натискання;
mousedown і mouseup — натискання та відпускання кнопки миші;
mousemove — рух курсора;
keydown і keyup — натискання та відпускання клавіші;
input — зміна значення поля під час введення;
submit — відправлення форми.
Браузер також створює події:
DOMContentLoaded — HTML було завантажено та розібрано;
load — сторінка та її ресурси завантажилися;
resize — змінився розмір вікна;
scroll — сторінку прокрутили;
error — сталася помилка завантаження або виконання.
JavaScript може самостійно запустити подію. Це потрібно, наприклад, для взаємодії між частинами застосунку.
const button = document.querySelector('#saveButton');
button.addEventListener('saved', function () {
console.log('Дані збережено');
});
button.dispatchEvent(new Event('saved'));Метод dispatchEvent запускає подію на вказаному об’єкті. У цьому випадку обробник виведе повідомлення в консоль.
Джерелом події називають об’єкт, на якому вона виникла або була запущена. У браузері такими об’єктами можуть бути:
HTML-елементи;
об’єкт document;
об’єкт window;
об’єкти форм;
деякі об’єкти браузерних API.
Кнопки, поля, посилання та інші елементи можуть створювати події взаємодії.
<input id="nameInput" placeholder="Введіть ім’я">
<p id="result"></p>
<script>
const input = document.querySelector('#nameInput');
const result = document.querySelector('#result');
input.addEventListener('input', function () {
result.textContent = `Ви ввели: ${input.value}`;
});
</script>Подія input виникає щоразу, коли користувач змінює значення поля.
documentdocument представляє HTML-документ. На ньому можна слухати події, пов’язані з усією сторінкою.
document.addEventListener('keydown', function (event) {
console.log(`Натиснуто клавішу: ${event.key}`);
});Обробник спрацює, коли користувач натисне клавішу, перебуваючи на сторінці.
windowwindow представляє вікно або вкладку браузера. На ньому часто обробляють події, пов’язані з розміром вікна та прокручуванням:
window.addEventListener('resize', function () {
console.log(`Ширина вікна: ${window.innerWidth}`);
});Основний сучасний спосіб підписатися на подію — метод addEventListener:
object.addEventListener(eventType, handler);Тут:
object — джерело події;
eventType — назва події у вигляді рядка;
handler — функція, яку потрібно виконати.
Приклад:
const button = document.querySelector('#button');
function handleClick() {
console.log('Кнопку натиснуто');
}
button.addEventListener('click', handleClick);Функція не повинна викликатися під час підписки. Потрібно передати саму функцію:
button.addEventListener('click', handleClick);А не результат її виклику:
// Неправильно: функція виконається одразу
button.addEventListener('click', handleClick());Обробник можна записати без окремого імені:
button.addEventListener('click', function () {
console.log('Натискання');
});Також можна використати стрілкову функцію:
button.addEventListener('click', () => {
console.log('Натискання');
});Якщо обробник потрібно буде видалити, зручніше зберегти його в змінній або оголосити окремою функцією.
Коли браузер викликає обробник, він передає йому об’єкт події. Цей об’єкт містить інформацію про те, що сталося.
<button id="infoButton">Натисніть мене</button>
<script>
const button = document.querySelector('#infoButton');
button.addEventListener('click', function (event) {
console.log(event.type);
console.log(event.target);
console.log(event.clientX);
console.log(event.clientY);
});
</script>Об’єкт event у цьому прикладі містить:
event.type — тип події, наприклад 'click';
event.target — об’єкт, на якому виникла подія;
event.clientX — горизонтальна координата курсора;
event.clientY — вертикальна координата курсора.
Вміст об’єкта залежить від типу події. Для клавіатурної події корисними є key і code:
document.addEventListener('keydown', function (event) {
console.log(`Символ: ${event.key}`);
console.log(`Код клавіші: ${event.code}`);
});Для події форми можна отримати саму форму через event.target.
target і currentTargetУ подіях часто використовують дві властивості:
target — елемент, на якому подія виникла;
currentTarget — елемент, на якому зараз виконується обробник.
У простому випадку вони однакові:
button.addEventListener('click', function (event) {
console.log(event.target === event.currentTarget);
});Але вони можуть відрізнятися, коли подія проходить через вкладені елементи:
<div id="panel">
<button id="actionButton">Натисніть</button>
</div>
<script>
const panel = document.querySelector('#panel');
panel.addEventListener('click', function (event) {
console.log(event.target); // button
console.log(event.currentTarget); // div
});
</script>Якщо натиснути кнопку:
event.target буде кнопкою;
event.currentTarget буде div, бо саме на ньому зареєстрований обробник.
Подія, яка виникла на вкладеному елементі, може поширитися до його батьків. Такий механізм називають спливанням події.
<div id="outer">
<button id="inner">Натисніть</button>
</div>
<script>
const outer = document.querySelector('#outer');
const inner = document.querySelector('#inner');
outer.addEventListener('click', function () {
console.log('Обробник div');
});
inner.addEventListener('click', function () {
console.log('Обробник button');
});
</script>Після натискання кнопки в консолі зазвичай з’явиться:
Обробник button
Обробник divСпочатку обробляється подія на кнопці, а потім вона спливає до div.
Метод stopPropagation() забороняє події переходити до батьківських елементів:
inner.addEventListener('click', function (event) {
event.stopPropagation();
console.log('Спрацювала лише кнопка');
});Використовуйте цей метод обережно. Без потреби зупиняти поширення не варто, оскільки інші частини програми можуть очікувати на цю подію.
Завдяки спливанню можна зареєструвати один обробник на батьківському елементі замість окремого обробника для кожної кнопки.
<ul id="tasks">
<li><button data-id="1">Завдання 1</button></li>
<li><button data-id="2">Завдання 2</button></li>
<li><button data-id="3">Завдання 3</button></li>
</ul>
<script>
const tasks = document.querySelector('#tasks');
tasks.addEventListener('click', function (event) {
const button = event.target.closest('button');
if (!button) {
return;
}
console.log(`Вибрано завдання ${button.dataset.id}`);
});
</script>Один обробник на ul реагує на натискання всіх кнопок усередині нього. Такий підхід називають делегуванням подій.
Метод closest('button') знаходить найближчу кнопку серед самого елемента та його батьків. Перевірка if (!button) потрібна, щоб не обробляти натискання на інші частини списку.
Деякі елементи мають стандартну поведінку:
посилання переходить на іншу адресу;
форма перезавантажує сторінку після відправлення;
кнопка в деяких випадках відправляє форму.
Метод preventDefault() скасовує таку поведінку.
<form id="registrationForm">
<input name="username" required>
<button type="submit">Зареєструватися</button>
</form>
<p id="status"></p>
<script>
const form = document.querySelector('#registrationForm');
const status = document.querySelector('#status');
form.addEventListener('submit', function (event) {
event.preventDefault();
const formData = new FormData(form);
const username = formData.get('username');
status.textContent = `Користувач ${username} готовий до реєстрації`;
});
</script>Форма не перезавантажує сторінку, а JavaScript сам обробляє її дані.
preventDefault() і stopPropagation() вирішують різні завдання:
preventDefault() скасовує стандартну дію браузера;
stopPropagation() зупиняє поширення події між елементами.
Для видалення обробника потрібно передати той самий об’єкт функції, який використовувався під час підписки:
function handleResize() {
console.log('Розмір вікна змінився');
}
window.addEventListener('resize', handleResize);
window.removeEventListener('resize', handleResize);Це не спрацює з двома різними анонімними функціями:
// Неправильно: це дві різні функції
button.addEventListener('click', function () {
console.log('Натискання');
});
button.removeEventListener('click', function () {
console.log('Натискання');
});Щоб видалити обробник, функцію потрібно зберегти:
function handleClick() {
console.log('Натискання');
}
button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick);Якщо обробник має спрацювати лише один раз, можна передати третій аргумент із параметром once:
button.addEventListener('click', function () {
console.log('Це повідомлення з’явиться лише один раз');
}, { once: true });Після першого натискання браузер автоматично видалить цей обробник.
Нижче наведено невеликий приклад, який поєднує кілька типів подій:
<!doctype html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<title>Модель подій</title>
</head>
<body>
<h1>Список покупок</h1>
<form id="itemForm">
<input id="itemInput" placeholder="Назва товару" required>
<button type="submit">Додати</button>
</form>
<ul id="itemList"></ul>
<p id="message"></p>
<script>
const form = document.querySelector('#itemForm');
const input = document.querySelector('#itemInput');
const list = document.querySelector('#itemList');
const message = document.querySelector('#message');
form.addEventListener('submit', function (event) {
// Скасовуємо перезавантаження сторінки
event.preventDefault();
const item = document.createElement('li');
item.innerHTML = `
<span>${input.value}</span>
<button type="button" data-action="remove">Видалити</button>
`;
list.append(item);
message.textContent = 'Товар додано';
input.value = '';
input.focus();
});
list.addEventListener('click', function (event) {
const removeButton = event.target.closest('[data-action="remove"]');
if (!removeButton) {
return;
}
removeButton.parentElement.remove();
message.textContent = 'Товар видалено';
});
input.addEventListener('input', function () {
message.textContent = `Довжина назви: ${input.value.length}`;
});
</script>
</body>
</html>У прикладі:
подія submit обробляє відправлення форми;
preventDefault() не дає сторінці перезавантажитися;
подія input відстежує введення тексту;
обробник click на списку використовує делегування;
кнопки видалення можуть бути створені після початкового завантаження сторінки, але обробник на списку все одно працює.
// Неправильно
button.addEventListener('click', handleClick());Функція виконається одразу, а не після натискання.
Правильно:
button.addEventListener('click', handleClick);Якщо скрипт виконується до появи елемента в документі, querySelector може повернути null.
const button = document.querySelector('#button');
button.addEventListener('click', handleClick);Переконайтеся, що скрипт розташований після потрібного HTML або запускайте код після DOMContentLoaded:
document.addEventListener('DOMContentLoaded', function () {
const button = document.querySelector('#button');
button.addEventListener('click', function () {
console.log('Кнопку натиснуто');
});
});target і currentTargetЯкщо обробник зареєстрований на батьківському елементі, target може бути вкладеною кнопкою або іншим дочірнім елементом. Для доступу до елемента, на якому встановлено обробник, використовуйте currentTarget.
onclickТакий запис можливий:
button.onclick = function () {
console.log('Натискання');
};Але наступне присвоєння замінить попередній обробник. Метод addEventListener гнучкіший: він дозволяє додати кілька обробників одного типу та окремо видаляти їх.
preventDefault() без причиниЯкщо викликати preventDefault() для кожної події, можна випадково зламати стандартну поведінку посилань, форм або елементів керування. Скасовуйте дію лише тоді, коли програма справді має замінити її власною логікою.
Подія повідомляє JavaScript про дію користувача, роботу браузера або дію програми.
Джерелами подій можуть бути HTML-елементи, document, window та інші об’єкти браузера.
Для підписки зазвичай використовують addEventListener.
Обробник отримує об’єкт події з інформацією про те, що сталося.
event.target — джерело події, а event.currentTarget — об’єкт із поточним обробником.
Події можуть спливати від вкладених елементів до батьківських.
stopPropagation() зупиняє поширення події.
preventDefault() скасовує стандартну дію браузера.
Делегування подій дає змогу обробляти події дочірніх елементів через одного батьківського обробника.