Кратко
Событие проходит три фазы: погружение (capture) — от document к элементу, target — на самом элементе, всплытие (bubbling) — от элемента обратно к document. По умолчанию addEventListener слушает фазу всплытия. stopPropagation() останавливает дальнейшее распространение. event.target — тот, кто вызвал, event.currentTarget — тот, кто слушает.
Подробно
Три фазы propagation:
- CAPTURING PHASE — событие идёт СВЕРХУ ВНИЗ: document → html → body → div → button
- TARGET PHASE — событие на целевом элементе (button)
- BUBBLING PHASE — событие идёт СНИЗУ ВВЕРХ: button → div → body → html → document
Визуально:
document ↓ (capture) html ↓ body ↓ div#outer ↓ button ← TARGET ↑ (bubbling) div#outer ↑ body ↑ html ↑ document
По умолчанию addEventListener слушает фазу BUBBLING:
div.addEventListener('click', () => console.log('div')); // при клике на button: сначала 'div' (bubbling)
Чтобы слушать CAPTURING:
div.addEventListener('click', handler, { capture: true });
stopPropagation():
button.addEventListener('click', (e) => { e.stopPropagation(); // событие дальше НЕ идёт console.log('Только здесь'); }); // div и body НЕ увидят клик
Важно: stopPropagation() останавливает propagation, но НЕ default action. Это разные механизмы (см. DA4).
Ментальная модель
Событие — как мяч, брошенный с крыши. Capture — мяч падает вниз (document → element). Target — мяч ударяется о землю (element). Bubbling — мяч отскакивает вверх (element → document). Каждый уровень (level) может поймать мяч (listener) или остановить его (stopPropagation).
Примеры
**Самый простой:**
<div id="outer">
<div id="inner">
<button>Клик</button>
</div>
</div>
<script>
document.getElementById('outer').addEventListener('click', () => {
console.log('outer');
});
document.getElementById('inner').addEventListener('click', () => {
console.log('inner');
});
// Клик на button:
// outer, inner — bubbling: сначала outer, потом inner
// Нет! Bubbling идёт СНИЗУ ВВЕРХ: inner → outer
</script>Bubbling: клик на button всплывает сначала к inner, потом к outer.
**Простой:**
<div id="outer">
<button>Клик</button>
</div>
<script>
// По умолчанию: bubbling (false)
document.getElementById('outer').addEventListener('click', () => {
console.log('bubbling');
}, false);
// Capture: true
document.getElementById('outer').addEventListener('click', () => {
console.log('capturing');
}, true);
// Клик на button:
// capturing → bubbling
</script>Порядок: capture (сверху вниз) → target → bubbling (снизу вверх).
**Реальный пример:**
<div id="modal">
<div class="modal-content">
<button class="close">×</button>
</div>
</div>
<script>
// Закрытие модалки при клике на фон
const modal = document.getElementById('modal');
const content = document.querySelector('.modal-content');
modal.addEventListener('click', (e) => {
// Закрываем только при клике на фон (не на контент)
if (e.target === modal) {
modal.style.display = 'none';
}
});
// Кнопка закрытия
const closeBtn = document.querySelector('.close');
closeBtn.addEventListener('click', (e) => {
e.stopPropagation(); // не даём событию дойти до modal
modal.style.display = 'none';
});Реальный паттерн: модальное окно с остановкой propagation для кнопки.
Частые ошибки
**Неправильно:** Думать, что bubbling идёт сверху вниз
**Почему:** Bubbling идёт СНИЗУ ВВЕРХ: от target к document. Capture — сверху вниз.
**Правильно:** Bubbling = снизу вверх. Capture = сверху вниз.
**Неправильно:** Путать stopPropagation и preventDefault
**Почему:** stopPropagation останавливает распространение. preventDefault останавливает действие браузера.
**Правильно:** Разные механизмы. Подробнее — в уроке DA4.
**Неправильно:** Считать, что все события всплывают
**Почему:** focus, blur, scroll НЕ всплывают.Большинство событий всплывают, но не все.
**Правильно:** Проверяйте спецификацию: большинство событий всплывают, но есть исключения.
Важно запомнить
- Capture: document → element (сверху вниз)
- Bubbling: element → document (снизу вверх)
- По умолчанию addEventListener = bubbling
- capture: true = слушать на фазе capture
- stopPropagation() останавливает распространение
- stopPropagation ≠ preventDefault
Связь
Назад: Вы умеете подписываться на события (DA1). Теперь вы понимаете, как события перемещаются по вложенным элементам.
Вперёд: Следующий урок (DA3) использует всплытие для делегирования событий — один обработчик для множества элементов.