Коротка відповідь
juniorПодія bubbling – це процес, коли після виконання event handler на елементі, подія переходить до його батьківських елементів у DOM-дереві. Кожен рівень викликає відповідний handler, якщо він зареєстрований, доки не досягне кореня або не буде зупинено методом stopPropagation(). Це дозволяє обробляти події на високому рівні, зменшуючи кількість слухачів.
Повне пояснення
Що це і навіщо Подія bubbling – механізм, що дозволяє одній події «піднятися» від конкретного елемента до його батьків, що спрощує обробку подій у великих DOM‑деревах.
Ключові принципи
- Подія спочатку виконується на елементі, де вона була ініційована (target).
- Потім переходить до батьківського елемента, і так далі, поки не досягне document або window.
- Якщо на будь‑якому рівні викликано
event.stopPropagation(), подальше поширення припиняється.
Як це працює
- Користувач взаємодіє з елементом (наприклад, клікає на кнопку).
- Відбувається виклик
click‑handler на цій кнопці. - Після завершення handler’у, браузер викликає
click‑handler на батьківському елементі (наприклад,<div>), а потім на його батьку і так далі.
Практика та реалізація
// HTML
<div id="parent">
<button id="child">Click me</button>
</div>
// JS
document.getElementById('child').addEventListener('click', e => {
console.log('Child handler');
});
document.getElementById('parent').addEventListener('click', e => {
console.log('Parent handler');
});
У результаті при кліку на кнопку виведуться обидва повідомлення.
Тестування
import { fireEvent } from '@testing-library/react';
test('bubbling works', () => {
const parent = jest.fn();
const child = jest.fn();
document.body.innerHTML = `<div id="parent"><button id="child">Btn</button></div>`;
document.getElementById('parent')!.addEventListener('click', parent);
document.getElementById('child')!.addEventListener('click', child);
fireEvent.click(document.getElementById('child')!);
expect(child).toHaveBeenCalled();
expect(parent).toHaveBeenCalled();
});
Оптимізація та edge cases
- Якщо потрібно обробити подію лише на конкретному елементі, використовуйте
event.stopPropagation(). - Для великих списків елементів розгляньте delegation: один слухач на батьку.
- У випадках, коли потрібен лише capture‑фаза, використовуйте третій аргумент
trueабо{capture: true}.
Часті помилки
- Забудьте про
stopPropagation()→ непередбачувана обробка. - Використання
addEventListenerбез перевірки на дублювання → подвійні виклики. - Не враховуєте, що
event.targetможе бути дочірнім елементом. - Не розумієте різницю між bubbling і capturing.
- Відсутність підтримки старих браузерів (IE <9) →
attachEvent. - Перевантаження одного слухача на великому DOM → продуктивність.
- Не очищуєте слухачі після unmount у React, що призводить до memory leaks.
- Не враховуєте
pointer-events: none→ подія не досягає елемента.
Дизайн‑рішення
- Для реактивних фреймворків (React, Vue) використовуйте synthetic events або
useEventListenerз бібліотек. - У Next.js 15 можна обробляти події на сервері через API‑роут, але bubbling відбувається лише в клієнтському коді.
Висновок Bubbling – це фундаментальний механізм DOM, що дозволяє централізовано обробляти події. Розуміння його роботи критично для ефективної розробки UI‑компонентів і оптимізації продуктивності.