← Назад к вопросам

В каком порядке сработают обработчики клика на div с вложенной кнопкой

2.3 Middle🔥 131 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Порядок срабатывания обработчиков клика на вложенные элементы

Фаза события определяет порядок срабатывания обработчиков. Когда вы кликаете на вложенный элемент, событие проходит три фазы: захват (capturing), целевую фазу (target) и всплытие (bubbling).

Три фазы события

При клике на кнопку, вложенную в div:

<div id="outer">
  <button id="btn">Нажми меня</button>
</div>

Порядок выполнения:

  1. Фаза захвата (Capturing) - событие идет сверху вниз: window -> document -> html -> body -> div -> button
  2. Целевая фаза (Target) - событие достигает самого элемента (button)
  3. Фаза всплытия (Bubbling) - событие идет снизу вверх: button -> div -> body -> html -> document -> window

Практический пример

const outer = document.getElementById('outer');
const btn = document.getElementById('btn');

// Обработчик на div - фаза всплытия (по умолчанию)
outer.addEventListener('click', () => {
  console.log('1. DIV - всплытие');
});

// Обработчик на div - фаза захвата
outer.addEventListener('click', () => {
  console.log('2. DIV - захват');
}, true);

// Обработчик на кнопку
btn.addEventListener('click', () => {
  console.log('3. BTN - целевая фаза');
});

Результат в консоли:

2. DIV - захват
3. BTN - целевая фаза
1. DIV - всплытие

Порядок по умолчанию (фаза всплытия)

Если вы не указываете третий параметр addEventListener, происходит всплытие:

const parent = document.getElementById('parent');
const child = document.getElementById('child');

parent.addEventListener('click', () => {
  console.log('Клик на parent (всплытие)');
});

child.addEventListener('click', () => {
  console.log('Клик на child');
});

// При клике на child выведет:
// 'Клик на child'
// 'Клик на parent (всплытие)'

Контроль фаз

// Фаза всплытия (useCapture = false, по умолчанию)
element.addEventListener('click', handler, false);

// Фаза захвата (useCapture = true)
element.addEventListener('click', handler, true);

Остановка распространения события

stopPropagation() - останавливает распространение события (не будет всплытия/захвата на родителей):

button.addEventListener('click', (event) => {
  event.stopPropagation();
  console.log('Клик на кнопку');
});

div.addEventListener('click', () => {
  console.log('Это никогда не выполнится');
});

stopImmediatePropagation() - останавливает и всплытие, и остальные обработчики на этом же элементе:

button.addEventListener('click', (event) => {
  event.stopImmediatePropagation();
  console.log('Первый обработчик');
});

button.addEventListener('click', () => {
  console.log('Это не выполнится');
});

Сложный пример с несколькими уровнями

<div id="level1" class="level-1">
  <div id="level2" class="level-2">
    <button id="btn" class="btn">Клик</button>
  </div>
</div>
document.getElementById('level1').addEventListener('click', () => {
  console.log('Level 1 - всплытие');
});

document.getElementById('level2').addEventListener('click', () => {
  console.log('Level 2 - всплытие');
});

document.getElementById('btn').addEventListener('click', () => {
  console.log('Button - целевая фаза');
});

// При клике на кнопку:
// 'Button - целевая фаза'
// 'Level 2 - всплытие'
// 'Level 1 - всплытие'

Полный порядок фаз

Для структуры с захватом:

// Все три элемента с захватом и всплытием
level1.addEventListener('click', () => console.log('L1 захват'), true);
level2.addEventListener('click', () => console.log('L2 захват'), true);
btn.addEventListener('click', () => console.log('BTN захват'), true);

level1.addEventListener('click', () => console.log('L1 всплытие'), false);
level2.addEventListener('click', () => console.log('L2 всплытие'), false);
btn.addEventListener('click', () => console.log('BTN всплытие'), false);

// Результат:
// 'L1 захват'      - фаза захвата
// 'L2 захват'      - фаза захвата
// 'BTN захват'     - фаза захвата
// 'BTN всплытие'   - целевая фаза (всплытие)
// 'L2 всплытие'    - фаза всплытия
// 'L1 всплытие'    - фаза всплытия

Практический совет

В большинстве случаев используй всплытие (значение false или просто опусти параметр) - это проще и интуитивнее. Захват редко требуется, основной его сценарий - предотвращение всплытия на ранней стадии.