Пошук уроків, статей та іншого контенту
Додаватимете обробники подій і керуватимете поширенням подій у DOM-дереві.
Подія — це повідомлення про те, що в браузері щось сталося. Наприклад:
користувач натиснув кнопку;
ввів текст у поле;
навів курсор на елемент;
відправив форму;
прокрутив сторінку;
натиснув клавішу.
JavaScript може реагувати на ці дії за допомогою обробників подій. Обробник — це функція, яку браузер викликає, коли відбувається певна подія.
Наприклад, після натискання кнопки можна змінити її текст:
<button id="helloButton">Привітатися</button>
<script>
const button = document.querySelector("#helloButton");
button.addEventListener("click", function () {
button.textContent = "Привіт!";
});
</script>Метод addEventListener додає обробник події до елемента.
addEventListenerЗагальний синтаксис:
element.addEventListener(eventName, handler);element — елемент, який має реагувати на подію;
eventName — назва події, наприклад "click";
handler — функція, яку потрібно виконати.
Обробник можна записати як окрему функцію:
const button = document.querySelector("#saveButton");
function saveData() {
console.log("Дані збережено");
}
button.addEventListener("click", saveData);Або як стрілкову функцію:
button.addEventListener("click", () => {
console.log("Дані збережено");
});| Подія | Коли виникає | |---|---| | click | після натискання на елемент | | dblclick | після подвійного натискання | | input | після зміни значення поля під час введення | | change | після зміни значення, коли поле втрачає фокус | | submit | після відправлення форми | | keydown | після натискання клавіші | | keyup | після відпускання клавіші | | mouseenter | коли курсор входить на елемент | | mouseleave | коли курсор залишає елемент | | focus | коли елемент отримує фокус | | blur | коли елемент втрачає фокус |
Браузер передає обробнику об’єкт події. Зазвичай його називають event або скорочено event/e.
const input = document.querySelector("#name");
input.addEventListener("input", (event) => {
console.log(event.target.value);
});Властивість event.target містить елемент, на якому безпосередньо відбулася подія.
У прикладі event.target.value — поточне значення поля введення.
Для подій клавіатури можна отримати натиснуту клавішу через event.key:
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
console.log("Користувач натиснув Escape");
}
});Деякі клавіші мають спеціальні назви:
"Enter" — Enter;
"Escape" — Escape;
" " — пробіл;
"ArrowUp" — стрілка вгору;
"ArrowDown" — стрілка вниз.
Деякі елементи мають стандартну поведінку. Наприклад, після відправлення форми браузер зазвичай перезавантажує сторінку.
Метод event.preventDefault() скасовує стандартну дію браузера.
<form id="loginForm">
<label>
Ім'я користувача:
<input id="username" name="username" required>
</label>
<button type="submit">Увійти</button>
</form>
<p id="message"></p>
<script>
const form = document.querySelector("#loginForm");
const username = document.querySelector("#username");
const message = document.querySelector("#message");
form.addEventListener("submit", (event) => {
// Скасовуємо перезавантаження сторінки
event.preventDefault();
message.textContent = `Вітаємо, ${username.value}!`;
});
</script>preventDefault() не зупиняє поширення події. Він лише скасовує стандартну дію, пов’язану з подією.
Щоб видалити обробник, потрібно передати в removeEventListener ту саму функцію, яку передавали в addEventListener.
const button = document.querySelector("#button");
function showMessage() {
console.log("Кнопку натиснуто");
}
button.addEventListener("click", showMessage);
// Через деякий час цей обробник більше не працюватиме
button.removeEventListener("click", showMessage);Анонімну функцію, створену безпосередньо під час виклику addEventListener, видалити таким способом не можна:
button.addEventListener("click", () => {
console.log("Повідомлення");
});
// Це інша функція, тому обробник не буде видалено
button.removeEventListener("click", () => {
console.log("Повідомлення");
});DOM має деревоподібну структуру. Наприклад:
<div class="card">
<button>Натиснути</button>
</div>Коли користувач натискає кнопку, подія пов’язана не лише з кнопкою. Вона поширюється через батьківські елементи.
Поширення події має такі етапи:
Фаза занурення — подія рухається від document до цільового елемента.
Фаза цілі — подія досягає елемента, на якому відбулася дія.
Фаза спливання — подія рухається від цільового елемента назад до document.
За замовчуванням обробники працюють на фазі спливання.
<div id="container">
<button id="button">Натиснути</button>
</div>
<script>
const container = document.querySelector("#container");
const button = document.querySelector("#button");
container.addEventListener("click", () => {
console.log("Обробник контейнера");
});
button.addEventListener("click", () => {
console.log("Обробник кнопки");
});
</script>Після натискання кнопки в консолі буде:
Обробник кнопки
Обробник контейнераСпочатку спрацьовує обробник кнопки, а потім подія спливає до контейнера.
Третій аргумент addEventListener може бути об’єктом із властивістю capture:
container.addEventListener("click", () => {
console.log("Контейнер: фаза занурення");
}, { capture: true });Тепер обробник контейнера спрацює до обробника кнопки.
Те саме можна записати коротше:
container.addEventListener("click", () => {
console.log("Контейнер: фаза занурення");
}, true);На практиці найчастіше достатньо стандартної фази спливання.
Метод event.stopPropagation() зупиняє поширення події до інших елементів.
<div id="parent">
<button id="child">Натиснути</button>
</div>
<script>
const parent = document.querySelector("#parent");
const child = document.querySelector("#child");
parent.addEventListener("click", () => {
console.log("Подія дійшла до батьківського елемента");
});
child.addEventListener("click", (event) => {
// Подія не спливе до батьківського елемента
event.stopPropagation();
console.log("Натиснуто кнопку");
});
</script>У цьому прикладі спрацює лише обробник кнопки.
Метод stopImmediatePropagation() зупиняє не тільки поширення події, а й виконання інших обробників цієї самої події на поточному елементі. Використовуйте його обережно.
Делегування подій — це додавання одного обробника до батьківського елемента замість окремого обробника для кожного дочірнього елемента.
Це особливо корисно для списків:
<ul id="tasks">
<li>Вивчити події <button data-action="remove">Видалити</button></li>
<li>Попрактикуватися <button data-action="remove">Видалити</button></li>
</ul>
<script>
const tasks = document.querySelector("#tasks");
tasks.addEventListener("click", (event) => {
const button = event.target.closest("button[data-action='remove']");
if (!button) {
return;
}
const task = button.closest("li");
task.remove();
});
</script>У цьому прикладі:
обробник додано лише до ul;
подія від кнопки спливає до ul;
event.target допомагає знайти елемент, на якому відбулося натискання;
closest() знаходить найближчий відповідний елемент;
remove() видаляє завдання.
Делегування також працює для елементів, які будуть додані до списку пізніше.
Нижче наведено невеликий список завдань. Користувач може:
додати завдання;
позначити його виконаним;
видалити завдання;
натиснути Enter у полі введення замість кнопки.
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<title>Список завдань</title>
<style>
.completed {
text-decoration: line-through;
color: gray;
}
li {
margin: 8px 0;
}
button {
margin-left: 8px;
}
</style>
</head>
<body>
<h1>Мої завдання</h1>
<form id="taskForm">
<input
id="taskInput"
type="text"
placeholder="Нове завдання"
required
>
<button type="submit">Додати</button>
</form>
<ul id="taskList"></ul>
<script>
const form = document.querySelector("#taskForm");
const input = document.querySelector("#taskInput");
const list = document.querySelector("#taskList");
form.addEventListener("submit", (event) => {
// Не перезавантажуємо сторінку після відправлення форми
event.preventDefault();
const text = input.value.trim();
if (text === "") {
return;
}
const item = document.createElement("li");
item.innerHTML = `
<span>${text}</span>
<button type="button" data-action="complete">
Виконано
</button>
<button type="button" data-action="remove">
Видалити
</button>
`;
list.append(item);
input.value = "";
input.focus();
});
list.addEventListener("click", (event) => {
const action = event.target.dataset.action;
const item = event.target.closest("li");
if (!item) {
return;
}
if (action === "complete") {
item.classList.toggle("completed");
}
if (action === "remove") {
item.remove();
}
});
</script>
</body>
</html>Обробник списку використовує делегування. Тому не потрібно додавати окремі обробники до кожної нової кнопки.
У реальному застосунку дані користувача потрібно безпечно вставляти в DOM. Використання
innerHTMLіз неперевіреним текстом може створити ризик виконання небезпечного HTML або JavaScript. Для простих навчальних прикладів безпечніше створювати елементи черезcreateElementі встановлювати текст черезtextContent.
Неправильно:
button.addEventListener("click", showMessage());showMessage() викликається одразу, а результат її виконання передається як обробник.
Правильно:
button.addEventListener("click", showMessage);Назви подій пишуться рядком і зазвичай у нижньому регістрі:
button.addEventListener("click", handler);Неправильно:
button.addEventListener("Click", handler);Якщо скрипт виконується до появи елемента в DOM, querySelector може повернути null.
Один із варіантів — розмістити script перед закривальним тегом body:
<body>
<button id="button">Натиснути</button>
<script src="script.js"></script>
</body>Інший варіант — дочекатися події DOMContentLoaded:
document.addEventListener("DOMContentLoaded", () => {
const button = document.querySelector("#button");
button.addEventListener("click", () => {
console.log("Кнопку натиснуто");
});
});preventDefault() без потребиpreventDefault() скасовує стандартну дію браузера. Якщо викликати його для посилання або форми без власної альтернативної логіки, елемент може перестати працювати очікуваним чином.
stopPropagation()Зупинка поширення може порушити роботу інших обробників, зокрема обробників батьківських компонентів. Спочатку перевірте, чи можна розв’язати проблему без цього методу.
event.target у делегуванніЯкщо користувач натискає на вкладений елемент кнопки, event.target може бути не самою кнопкою. Для надійної перевірки часто використовують:
const button = event.target.closest("button");Подія повідомляє JavaScript про дію користувача або зміну стану браузера.
Обробники подій додають методом addEventListener.
Об’єкт події містить інформацію про подію та її джерело.
event.target — елемент, на якому безпосередньо відбулася подія.
preventDefault() скасовує стандартну дію браузера.
Події поширюються DOM-деревом від цільового елемента до його батьків.
stopPropagation() зупиняє поширення події.
Делегування дає змогу обробляти події дочірніх елементів через один обробник на батьківському елементі.
Обробник потрібно передавати як функцію, не викликаючи її під час налаштування.