Skip to main content

Метод event.stopPropagation()

event.stopPropagation() зупиняє подальше поширення події деревом DOM: подія відпрацює на тому елементі, де вона сталася, але вище, до батьківських вузлів, уже не підніметься. Метод впливає тільки на маршрут події. Він не скасовує стандартну дію браузера і не заважає іншим обробникам на тому самому елементі.

Теорія

TL;DR

  • stopPropagation() обриває поширення події далі по дереву: і спливання (bubbling) вгору, і подальше занурення (capturing) вниз.
  • Обробники, навішані на той самий елемент, усе одно виконаються: метод зупиняє сусідів по дереву, а не сусідів по елементу.
  • Стандартну дію браузера (перехід за посиланням, відправку форми) він не скасовує, для цього є preventDefault().
  • stopImmediatePropagation() жорсткіший: він зупиняє і поширення, і решту обробників на цьому ж елементі.
  • Зловживання методом тихо ламає делегування подій: батьківський обробник просто перестає отримувати кліки.

Швидкий приклад

javascript
document.querySelector('.child').addEventListener('click', (event) => { console.log('child'); event.stopPropagation(); // зупиняємо спливання, батько нічого не побачить });

Спливання подій за замовчуванням

Більшість подій у DOM спливають: після обробки на цільовому елементі вони йдуть угору по ланцюжку предків.

html
<div class="parent"> <button class="child">Натисни</button> </div>
javascript
document.querySelector('.parent').addEventListener('click', () => { console.log('Батько'); }); document.querySelector('.child').addEventListener('click', () => { console.log('Дитина'); });

Клік по кнопці .child дасть у консолі:

text
Дитина Батько

Спочатку спрацював обробник на кнопці, а потім подія спливла вгору і викликала обробник батька.

Що саме робить stopPropagation()

Досить викликати метод в обробнику дитини:

javascript
document.querySelector('.child').addEventListener('click', (event) => { console.log('Дитина'); event.stopPropagation(); // зупиняємо спливання });

Тепер клік по кнопці виводить лише:

text
Дитина

Подія не дійде до батька, вона «застрягне» на кнопці. Те саме працює на глибшій вкладеності:

html
<div id="outer"> <div id="inner"> <button id="btn">Click me</button> </div> </div>
javascript
outer.addEventListener('click', () => console.log('outer')); inner.addEventListener('click', () => console.log('inner')); btn.addEventListener('click', (e) => { e.stopPropagation(); console.log('button'); });

Клік по кнопці друкує лише button, а inner та outer події вже не отримають.

Делегування: коли спливання заважає

Якщо на батьківському елементі висить один спільний обробник (класичне делегування), інколи клік по вкладеній кнопці не повинен до нього доходити:

html
<ul id="list"> <li>Елемент 1 <button>Видалити</button></li> <li>Елемент 2 <button>Видалити</button></li> </ul>
javascript
list.addEventListener('click', (e) => { if (e.target.tagName === 'LI') { console.log('Клік по пункту'); } }); document.querySelectorAll('button').forEach(btn => btn.addEventListener('click', (e) => { e.stopPropagation(); // щоб батько не отримав подію console.log('Видалення елемента'); }) );

Результат:

  • клік по <li> виводить «Клік по пункту»;
  • клік по кнопці виводить «Видалення елемента», і подія не спливає до списку.

Чого stopPropagation() не робить

  • Не скасовує стандартну дію браузера. Форма все одно відправиться, посилання все одно відкриється. Для цього потрібен event.preventDefault().
  • Не заважає іншим обробникам того самого елемента. Якщо на кнопці висить три слухачі click, усі три виконаються у порядку додавання.

stopImmediatePropagation() і підсумкова таблиця

Є жорсткіший варіант:

javascript
event.stopImmediatePropagation();

Він зупиняє все: і поширення події по дереву, і решту обробників на цьому ж елементі. Тобто повністю блокує подальшу обробку.

МетодЩо робитьЗупиняє спливання?Зупиняє інші обробники на елементі?
event.stopPropagation()Перериває поширення події далі по деревуТакНі
event.stopImmediatePropagation()Повністю блокує подальшу обробку подіїТакТак
event.preventDefault()Скасовує стандартну дію браузераНіНі

Коротка пам'ятка: stopPropagation() це «не піднімайся вище», preventDefault() це «не роби стандартну дію», stopImmediatePropagation() це «зупини все, навіть сусідів».

Типові помилки

  • Плутати з preventDefault(). Перший керує маршрутом події, другий, стандартною дією браузера. Щоб форма і не спливала, і не відправилась, потрібні обидва виклики.
  • Ставити stopPropagation() про всяк випадок у кожному обробнику. Це тихо ламає делегування подій і глобальні слухачі на document, наприклад закриття випадного меню по кліку поза ним.
  • Очікувати, що метод вимкне інші обробники цього ж елемента. Не вимкне, для цього є stopImmediatePropagation().
  • Забувати про фазу занурення. Якщо слухач додано з { capture: true }, виклик обірве подію ще до того, як вона дійде до цільового елемента.
  • Писати return false замість виклику. У звичайному DOM-обробнику це не робить нічого: така поведінка є лише в jQuery, де return false викликає обидва методи одразу.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.