Пошук уроків, статей та іншого контенту
Навчитеся реєструвати та видаляти обробники подій за допомогою addEventListener і removeEventListener.
Подія — це сигнал про те, що щось відбулося в браузері:
користувач натиснув кнопку;
ввів текст у поле;
навів курсор на елемент;
сторінка завантажилася;
клавіатура натиснула клавішу.
Обробник події — це функція, яка запускається у відповідь на певну подію.
Наприклад, можна виконати код після натискання кнопки:
<button id="greetButton">Привітатися</button>
<script>
const button = document.querySelector("#greetButton");
button.addEventListener("click", function () {
alert("Привіт!");
});
</script>Метод addEventListener реєструє обробник події для певного елемента.
addEventListenerelement.addEventListener(eventType, handler);Метод приймає щонайменше два аргументи:
eventType — назва події у вигляді рядка;
handler — функція, яку потрібно виконати.
Приклад:
const button = document.querySelector("#saveButton");
function saveData() {
console.log("Дані збережено");
}
button.addEventListener("click", saveData);У цьому прикладі:
"click" — назва події натискання;
saveData — функція-обробник;
функція saveData буде викликатися щоразу після натискання кнопки.
Потрібно передавати функцію, а не результат її виклику:
// Правильно
button.addEventListener("click", saveData);
// Неправильно
button.addEventListener("click", saveData());У неправильному варіанті saveData() виконається одразу, а його результат буде передано в addEventListener замість функції.
Також можна використовувати стрілкову функцію:
button.addEventListener("click", () => {
console.log("Кнопку натиснуто");
});Коли браузер викликає обробник, він передає йому об'єкт події. Цей об'єкт зазвичай називають event або eventObject.
const input = document.querySelector("#nameInput");
input.addEventListener("input", function (event) {
console.log("Поточне значення:", event.target.value);
});Властивість event.target містить елемент, на якому сталася подія.
У прикладі:
подія "input" виникає під час зміни тексту в полі;
event.target — це поле введення;
event.target.value — його поточне значення.
Те саме можна записати зі стрілковою функцією:
input.addEventListener("input", (event) => {
console.log(event.target.value);
});Найчастіше в браузері використовують такі події:
clickВиникає після натискання елемента.
button.addEventListener("click", () => {
console.log("Натискання");
});inputВиникає під час зміни значення поля введення.
input.addEventListener("input", (event) => {
console.log(event.target.value);
});changeВиникає після зміни значення елемента, коли користувач завершив редагування або вибір.
const select = document.querySelector("#colorSelect");
select.addEventListener("change", (event) => {
console.log("Вибраний колір:", event.target.value);
});submitВиникає під час надсилання форми.
const form = document.querySelector("#loginForm");
form.addEventListener("submit", (event) => {
event.preventDefault();
console.log("Форму оброблено без перезавантаження сторінки");
});Метод event.preventDefault() скасовує стандартну дію браузера. Для форми це зазвичай перезавантаження сторінки та надсилання даних на адресу з атрибута action.
keydownВиникає, коли користувач натискає клавішу.
document.addEventListener("keydown", (event) => {
console.log("Натиснуто клавішу:", event.key);
});Для одного елемента можна зареєструвати кілька обробників тієї самої події:
const button = document.querySelector("#button");
function logClick() {
console.log("Подія записана в журнал");
}
function showMessage() {
alert("Кнопку натиснуто");
}
button.addEventListener("click", logClick);
button.addEventListener("click", showMessage);Після натискання кнопки виконаються обидві функції.
Це одна з важливих переваг addEventListener порівняно з прямим присвоєнням властивості onclick:
button.onclick = logClick;
button.onclick = showMessage;У такому випадку друге присвоєння замінить перший обробник. addEventListener не замінює вже зареєстровані обробники.
removeEventListenerЩоб видалити обробник, використовують метод:
element.removeEventListener(eventType, handler);Наприклад:
const button = document.querySelector("#button");
function handleClick() {
console.log("Кнопку натиснуто");
}
button.addEventListener("click", handleClick);
// Пізніше обробник можна видалити
button.removeEventListener("click", handleClick);Після виклику removeEventListener функція handleClick більше не запускатиметься у відповідь на натискання цієї кнопки.
Браузер може видалити обробник лише тоді, коли передано те саме посилання на функцію:
function handleClick() {
console.log("Натискання");
}
button.addEventListener("click", handleClick);
button.removeEventListener("click", handleClick);Цей варіант не спрацює:
button.addEventListener("click", () => {
console.log("Натискання");
});
button.removeEventListener("click", () => {
console.log("Натискання");
});Хоча функції мають однаковий код, це два різні об'єкти-функції. Тому браузер не зможе знайти початковий обробник.
Якщо обробник потрібно буде видаляти, збережіть його у змінній або оголосіть окремою функцією:
const handleClick = () => {
console.log("Натискання");
};
button.addEventListener("click", handleClick);
// Посилання на ту саму функцію
button.removeEventListener("click", handleClick);Іноді обробник потрібно виконати лише один раз. Для цього можна передати третій аргумент з опцією once:
const button = document.querySelector("#showButton");
button.addEventListener(
"click",
() => {
console.log("Це повідомлення з'явиться лише один раз");
},
{ once: true }
);Після першого натискання браузер автоматично видалить цей обробник.
Нижче наведено невелику програму з кнопкою лічильника. Вона:
реагує на натискання кнопки;
збільшує лічильник;
дозволяє вимкнути обробник;
дозволяє знову його увімкнути.
<!doctype html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<title>Обробники подій</title>
</head>
<body>
<h1>Лічильник</h1>
<p>Натискань: <span id="counter">0</span></p>
<button id="countButton">Збільшити</button>
<button id="disableButton">Вимкнути обробник</button>
<button id="enableButton">Увімкнути обробник</button>
<script>
const counter = document.querySelector("#counter");
const countButton = document.querySelector("#countButton");
const disableButton = document.querySelector("#disableButton");
const enableButton = document.querySelector("#enableButton");
let count = 0;
function increaseCounter() {
count += 1;
counter.textContent = count;
}
countButton.addEventListener("click", increaseCounter);
disableButton.addEventListener("click", () => {
countButton.removeEventListener("click", increaseCounter);
});
enableButton.addEventListener("click", () => {
countButton.addEventListener("click", increaseCounter);
});
</script>
</body>
</html>Зверніть увагу, що для increaseCounter використовується одне й те саме посилання. Саме тому функцію можна і зареєструвати, і видалити.
Подія може поширюватися від вкладеного елемента до його батьківських елементів. Цей процес називається спливанням події.
<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>Якщо натиснути кнопку, у консоль буде виведено:
Подія на кнопці
Подія на контейнеріСпочатку спрацьовує обробник кнопки, а потім подія спливає до контейнера.
Метод stopPropagation() зупиняє поширення події до батьківських елементів:
button.addEventListener("click", (event) => {
event.stopPropagation();
console.log("Подія зупинена на кнопці");
});Використовуйте цей метод обережно. Часто краще перевірити, який саме елемент було натиснуто, ніж без потреби зупиняти поширення всіх подій.
Якщо потрібно обробляти натискання на багато схожих елементів, можна зареєструвати один обробник на їхньому спільному контейнері.
<ul id="tasks">
<li>Вивчити JavaScript</li>
<li>Виконати вправу</li>
<li>Повторити події</li>
</ul>
<script>
const tasks = document.querySelector("#tasks");
tasks.addEventListener("click", (event) => {
if (event.target.tagName === "LI") {
event.target.classList.toggle("completed");
}
});
</script>У цьому прикладі один обробник на ul реагує на натискання будь-якого li.
Делегування особливо корисне, коли:
елементів багато;
елементи додаються динамічно;
не потрібно реєструвати окремий обробник для кожного елемента.
// Неправильно
button.addEventListener("click", handleClick());Потрібно передати саму функцію:
// Правильно
button.addEventListener("click", handleClick);// Обробник зареєстровано
button.addEventListener("click", () => {
console.log("Клік");
});
// Інша функція не видалить початковий обробник
button.removeEventListener("click", () => {
console.log("Клік");
});Якщо обробник потрібно видаляти, використовуйте іменовану функцію або збережіть функцію у змінній.
Якщо скрипт виконується до того, як потрібний елемент з'явився в HTML, querySelector може повернути null.
const button = document.querySelector("#button");
button.addEventListener("click", handleClick);Щоб уникнути цієї проблеми, розміщуйте скрипт перед </body> або використовуйте атрибут defer:
<script src="script.js" defer></script>Назви подій чутливі до написання:
// Правильно
button.addEventListener("click", handleClick);
// Неправильно
button.addEventListener("Click", handleClick);Назви подій зазвичай записують малими літерами: "click", "input", "submit", "keydown".
Якщо один і той самий обробник реєструвати багато разів, він може виконуватися неочікувану кількість разів.
function handleClick() {
console.log("Клік");
}
button.addEventListener("click", handleClick);
button.addEventListener("click", handleClick);Для однакового посилання на функцію браузер не створює необмежену кількість ідентичних реєстрацій, але в реальному коді часто додаються різні функції або обробники реєструються в циклах. Стежте, де і коли виконується addEventListener.
Створіть HTML із кнопкою та абзацом. Реалізуйте таку поведінку:
Після натискання кнопки текст абзацу змінюється на "Подію оброблено".
Додайте окрему кнопку для видалення обробника.
Після видалення натискання першої кнопки більше не змінює текст.
Додайте кнопку для повторної реєстрації обробника.
Орієнтовна структура:
<p id="message">Очікування дії</p>
<button id="actionButton">Виконати дію</button>
<button id="removeButton">Видалити обробник</button>
<button id="addButton">Додати обробник</button>
<script>
const message = document.querySelector("#message");
const actionButton = document.querySelector("#actionButton");
const removeButton = document.querySelector("#removeButton");
const addButton = document.querySelector("#addButton");
function handleAction() {
message.textContent = "Подію оброблено";
}
actionButton.addEventListener("click", handleAction);
removeButton.addEventListener("click", () => {
actionButton.removeEventListener("click", handleAction);
});
addButton.addEventListener("click", () => {
actionButton.addEventListener("click", handleAction);
});
</script>Обробник події — це функція, яка виконується у відповідь на дію або подію браузера.
addEventListener реєструє обробник:
element.addEventListener("click", handler);removeEventListener видаляє раніше зареєстрований обробник:
element.removeEventListener("click", handler);Для видалення потрібно передати те саме посилання на функцію.
Об'єкт події містить інформацію про подію та елемент, на якому вона відбулася.
preventDefault() скасовує стандартну дію браузера.
stopPropagation() зупиняє поширення події до батьківських елементів.
Опція { once: true } дозволяє виконати обробник лише один раз.