Метод event.stopPropagation()
event.stopPropagation() зупиняє подальше поширення події деревом DOM: подія відпрацює на тому елементі, де вона сталася, але вище, до батьківських вузлів, уже не підніметься.
Метод впливає тільки на маршрут події. Він не скасовує стандартну дію браузера і не заважає іншим обробникам на тому самому елементі.
Теорія
TL;DR
stopPropagation()обриває поширення події далі по дереву: і спливання (bubbling) вгору, і подальше занурення (capturing) вниз.- Обробники, навішані на той самий елемент, усе одно виконаються: метод зупиняє сусідів по дереву, а не сусідів по елементу.
- Стандартну дію браузера (перехід за посиланням, відправку форми) він не скасовує, для цього є
preventDefault(). stopImmediatePropagation()жорсткіший: він зупиняє і поширення, і решту обробників на цьому ж елементі.- Зловживання методом тихо ламає делегування подій: батьківський обробник просто перестає отримувати кліки.
Швидкий приклад
document.querySelector('.child').addEventListener('click', (event) => {
console.log('child');
event.stopPropagation(); // зупиняємо спливання, батько нічого не побачить
});Спливання подій за замовчуванням
Більшість подій у DOM спливають: після обробки на цільовому елементі вони йдуть угору по ланцюжку предків.
<div class="parent">
<button class="child">Натисни</button>
</div>document.querySelector('.parent').addEventListener('click', () => {
console.log('Батько');
});
document.querySelector('.child').addEventListener('click', () => {
console.log('Дитина');
});Клік по кнопці .child дасть у консолі:
Дитина
БатькоСпочатку спрацював обробник на кнопці, а потім подія спливла вгору і викликала обробник батька.
Що саме робить stopPropagation()
Досить викликати метод в обробнику дитини:
document.querySelector('.child').addEventListener('click', (event) => {
console.log('Дитина');
event.stopPropagation(); // зупиняємо спливання
});Тепер клік по кнопці виводить лише:
ДитинаПодія не дійде до батька, вона «застрягне» на кнопці. Те саме працює на глибшій вкладеності:
<div id="outer">
<div id="inner">
<button id="btn">Click me</button>
</div>
</div>outer.addEventListener('click', () => console.log('outer'));
inner.addEventListener('click', () => console.log('inner'));
btn.addEventListener('click', (e) => {
e.stopPropagation();
console.log('button');
});Клік по кнопці друкує лише button, а inner та outer події вже не отримають.
Делегування: коли спливання заважає
Якщо на батьківському елементі висить один спільний обробник (класичне делегування), інколи клік по вкладеній кнопці не повинен до нього доходити:
<ul id="list">
<li>Елемент 1 <button>Видалити</button></li>
<li>Елемент 2 <button>Видалити</button></li>
</ul>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() і підсумкова таблиця
Є жорсткіший варіант:
event.stopImmediatePropagation();Він зупиняє все: і поширення події по дереву, і решту обробників на цьому ж елементі. Тобто повністю блокує подальшу обробку.
| Метод | Що робить | Зупиняє спливання? | Зупиняє інші обробники на елементі? |
|---|---|---|---|
event.stopPropagation() | Перериває поширення події далі по дереву | Так | Ні |
event.stopImmediatePropagation() | Повністю блокує подальшу обробку події | Так | Так |
event.preventDefault() | Скасовує стандартну дію браузера | Ні | Ні |
Коротка пам'ятка:
stopPropagation()це «не піднімайся вище»,preventDefault()це «не роби стандартну дію»,stopImmediatePropagation()це «зупини все, навіть сусідів».
Типові помилки
- Плутати з
preventDefault(). Перший керує маршрутом події, другий, стандартною дією браузера. Щоб форма і не спливала, і не відправилась, потрібні обидва виклики. - Ставити
stopPropagation()про всяк випадок у кожному обробнику. Це тихо ламає делегування подій і глобальні слухачі наdocument, наприклад закриття випадного меню по кліку поза ним. - Очікувати, що метод вимкне інші обробники цього ж елемента. Не вимкне, для цього є
stopImmediatePropagation(). - Забувати про фазу занурення. Якщо слухач додано з
{ capture: true }, виклик обірве подію ще до того, як вона дійде до цільового елемента. - Писати
return falseзамість виклику. У звичайному DOM-обробнику це не робить нічого: така поведінка є лише в jQuery, деreturn falseвикликає обидва методи одразу.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.