Какие знаешь стадии распространения событий?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Стадии распространения событий в DOM
Событие в браузере проходит через три основных стадии при распространении по дереву DOM. Это называется Event Flow или Event Propagation.
Три стадии распространения
1. Capturing Phase (Фаза захвата)
Событие начинает своё путешествие от корня DOM (window) и спускается вниз по иерархии к целевому элементу.
window → document → html → body → div → button (целевой элемент)
↓ Направление захвата
// Слушатель фазы захвата — третий параметр true
document.addEventListener('click', (event) => {
console.log('Capturing phase:', event.eventPhase);
}, true); // true = захват
// или
document.addEventListener('click', (event) => {
console.log('Capturing phase:', event.eventPhase);
}, { capture: true }); // Более читаемый синтаксис
2. Target Phase (Фаза цели)
Событие достигает целевого элемента, на котором произошло событие.
const button = document.querySelector('button');
button.addEventListener('click', (event) => {
console.log('Target phase:', event.eventPhase); // 2 (TARGET_PHASE)
});
3. Bubbling Phase (Фаза всплытия)
Событие «всплывает» обратно вверх по иерархии от целевого элемента к корню.
window ← document ← html ← body ← div ← button (целевой элемент)
↑ Направление всплытия
// Слушатель фазы всплытия — третий параметр false или опущен
document.addEventListener('click', (event) => {
console.log('Bubbling phase:', event.eventPhase); // 3 (BUBBLING_PHASE)
});
// или явно
document.addEventListener('click', (event) => {
console.log('Bubbling phase:', event.eventPhase);
}, false); // false = всплытие (default)
Пример с визуализацией
// HTML
<div class="outer">
<div class="middle">
<button class="inner">Click me</button>
</div>
</div>
// JavaScript
const outer = document.querySelector('.outer');
const middle = document.querySelector('.middle');
const inner = document.querySelector('.inner');
// CAPTURING фаза (спускаемся вниз)
outer.addEventListener('click', () => {
console.log('Outer - Capturing');
}, true);
middle.addEventListener('click', () => {
console.log('Middle - Capturing');
}, true);
// TARGET фаза (самый элемент)
inner.addEventListener('click', () => {
console.log('Inner - Target');
});
// BUBBLING фаза (поднимаемся вверх)
middle.addEventListener('click', () => {
console.log('Middle - Bubbling');
});
outer.addEventListener('click', () => {
console.log('Outer - Bubbling');
});
// При клике на кнопку консоль выведет:
// Outer - Capturing
// Middle - Capturing
// Inner - Target
// Middle - Bubbling
// Outer - Bubbling
Числовые значения eventPhase
event.eventPhase может принимать значения:
- 0 = NONE (событие не обрабатывается)
- 1 = CAPTURING_PHASE (фаза захвата)
- 2 = AT_TARGET (фаза цели)
- 3 = BUBBLING_PHASE (фаза всплытия)
Как управлять распространением
stopPropagation() — остановить дальнейшее распространение
inner.addEventListener('click', (event) => {
event.stopPropagation();
console.log('Inner clicked');
// Событие НЕ будет всплывать к middle и outer
});
middle.addEventListener('click', () => {
console.log('This won\'t be called');
});
stopImmediatePropagation() — остановить всё дальнейшее
button.addEventListener('click', (event) => {
event.stopImmediatePropagation();
console.log('First handler');
});
button.addEventListener('click', () => {
console.log('Second handler won\'t be called');
});
preventDefault() — отменить действие по умолчанию
// Отменит дефолтное поведение (отправку формы)
form.addEventListener('submit', (event) => {
event.preventDefault();
console.log('Form submission prevented');
});
// Событие ВСЕ РАВНО будет распространяться! preventDefault ≠ stopPropagation
Какие события имеют всплытие?
Не все события всплывают. Только события с bubbles: true:
// События которые всплывают (bubbles: true)
- click, dblclick
- mouseenter (НЕ всплывает, используй mouseover)
- mouseover, mouseout
- keydown, keyup
- focus (НЕ всплывает, используй focusin)
- change
- input
- submit
// События которые НЕ всплывают (bubbles: false)
- load, unload
- scroll
- resize
- focus, blur
- mouseenter, mouseleave
- play, pause (для медиа)
// Проверить, всплывает ли событие
const clickEvent = new MouseEvent('click');
console.log(clickEvent.bubbles); // true
const focusEvent = new FocusEvent('focus');
console.log(focusEvent.bubbles); // false
Event Delegation (Делегирование событий)
Использование всплытия для обработки событий на одном родительском элементе вместо множества дочерних:
// Вместо этого:
const buttons = document.querySelectorAll('button');
buttons.forEach(btn => {
btn.addEventListener('click', () => {
console.log('Button clicked');
});
});
// Делай это (делегирование):
const container = document.querySelector('.buttons-container');
container.addEventListener('click', (event) => {
if (event.target.tagName === 'BUTTON') {
console.log('Button clicked');
}
});
Преимущества:
- Меньше слушателей событий в памяти
- Работает и для динамически добавленных элементов
- Более производительно
Практический пример: форма с валидацией
const form = document.querySelector('form');
form.addEventListener('submit', (event) => {
// Оцени: что сработает первым?
// 1. Capturing phase на document
// 2. Bubbling phase от всех input внутри
// 3. Наш listener на форме
if (!isFormValid()) {
event.preventDefault();
event.stopPropagation(); // Останавливаем всплытие
}
});
Резюме
- Capturing — событие спускается от корня к элементу
- Target — событие обрабатывается на целевом элементе
- Bubbling — событие всплывает от элемента к корню
По умолчанию слушатели срабатывают в фазе всплытия. Используй третий параметр true для захвата. Контролируй распространение с stopPropagation(), но помни о делегировании — часто полезнее позволить событию всплыть.