Коротка відповідь
middleEvent bubbling — це процес, коли подія спочатку обробляється на найглибшому елементі DOM, а потім «піднімається» до батьківських вузлів. Event capturing (трап) — протилежний шлях: подія спочатку «захоплюється» на корені DOM і потім проходить до цільового елемента. Обидва механізми дозволяють керувати порядком обробки подій у вкладених елементах.
Повне пояснення
Що це і навіщо
- Event bubbling та capturing — два режими propagation у DOM, що визначають порядок обробки подій від цільового елемента до кореня і навпаки.
Ключові принципи
- Bubbling (підняття) – подія спочатку обробляється на елементі, де вона виникла, а потім «піднімається» через батьківські вузли.
- Capturing (захоплення) – подія «піймається» на шляху від кореня до цільового елемента.
- В обох випадках можна зупинити propagation за допомогою
event.stopPropagation()абоevent.stopImmediatePropagation().
Як це працює
- При виклику
addEventListener(type, handler, {capture: true})обробник підписується на фазу захоплення. - Якщо флаг
{capture: false}(або не вказано), обробник підписується на фазу bubbling. - Фаза target (ціль) виконується між захопленням і підняттям.
Практика та реалізація
// Capturing
document.addEventListener('click', handler, {capture: true});
// Bubbling (default)
document.addEventListener('click', handler);
Тестування
- У Jest можна перевірити порядок виклику обробників, використовуючи
jest.fn()і симуляцію подій черезdispatchEvent.
Особливості в контексті React
- У React події обгортаються у SyntheticEvent, який підтримує bubbling. Capturing можна реалізувати через
onClickCapture.
Оптимізація та edge cases
- Надмірне використання bubbling може призвести до непередбачуваних побічних ефектів, особливо при глибокій вкладеності.
- Для критичних подій (наприклад, клавіші Escape) часто використовують capturing, щоб перехопити їх на найвищому рівні.
Часті помилки
- Не розуміння, що
addEventListenerза замовчуванням працює в bubbling. - Застосування
stopPropagationу всіх обробниках, що блокує інші слушники. - Використання
event.targetзамістьthisу класових компонентах. - Забудова про фазу target, що може вплинути на логіку.
- Перевантаження кореневого елемента (наприклад,
document) обробниками. - Неочікуване перехоплення подій у фреймах (iframe).
- Відсутність
preventDefaultпри необхідності. - Використання
capture: trueу всіх обробниках, що знижує продуктивність.
Cheatsheet
capture: true→ capturing,falseабо не вказано → bubbling.event.stopPropagation()→ зупинити подальший propagation.event.stopImmediatePropagation()→ зупинити інші обробники на тому ж елементі.event.target→ елемент, де подія виникла;thisу синтетичних обробниках React → елемент, на якому підписано слухач.