DOM Advanced

Всплытие и погружение событий

Понять, как события проходят три фазы: capture → target → bubbling, и как контролировать propagation.

Продвинутый (Advanced)

Кратко

Событие проходит три фазы: погружение (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).


Примеры

**Самый простой:**

html
<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.

**Простой:**

html
<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 (снизу вверх).

**Реальный пример:**

html
<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) использует всплытие для делегирования событий — один обработчик для множества элементов.

Материалы курса DOM Advanced — PROlab Academy.