Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое всплытие (Event Bubbling)
Всплытие (bubbling) — это механизм распространения событий в DOM от элемента, где оно произошло, вверх к корневому элементу. Это один из трёх этапов обработки событий в JavaScript и важен для понимания делегирования событий.
Три этапа обработки событий
Событие проходит три фазы:
- Capturing (перехват) — событие идёт от
documentк элементу - Target (цель) — событие достигает целевого элемента
- Bubbling (всплытие) — событие идёт от элемента обратно к
document
┌─────────────────────────────────────────┐
│ document │
│ ↓ (capturing) ↑ (bubbling) │
│ ┌─────────────────────────────────┐ │
│ │ html │ │
│ │ ↓ (capturing) ↑ (bubbling) │ │
│ │ ┌──────────────────────────┐ │ │
│ │ │ body │ │ │
│ │ │ ↓ (capturing) ↑ (bubble)│ │ │
│ │ │ ┌──────────────────┐ │ │ │
│ │ │ │ div (target) │ │ │ │
│ │ │ │ ↓ click event │ │ │ │
│ │ │ └──────────────────┘ │ │ │
│ │ └──────────────────────────┘ │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
Практический пример
Давайте посмотрим, как событие click всплывает вверх:
<div id="parent" style="border: 2px solid blue; padding: 20px;">
<button id="child">Нажми на кнопку</button>
</div>
const parent = document.getElementById('parent');
const child = document.getElementById('child');
// Слушатель на кнопке
child.addEventListener('click', (event) => {
console.log('3. Клик на кнопку');
});
// Слушатель на родительском div
parent.addEventListener('click', (event) => {
console.log('2. Событие всплыло на parent div');
});
// Слушатель на document
document.addEventListener('click', (event) => {
console.log('1. Событие достигло document');
});
// Вывод при клике на кнопку:
// 3. Клик на кнопку
// 2. Событие всплыло на parent div
// 1. Событие достигло document
event.target vs event.currentTarget
Важно различать эти два свойства:
parent.addEventListener('click', (event) => {
console.log(event.target); // <button> (где произошло событие)
console.log(event.currentTarget); // <div> (где слушатель)
});
// При клике на кнопку:
// event.target = <button id="child">
// event.currentTarget = <div id="parent">
Остановка всплытия
child.addEventListener('click', (event) => {
event.stopPropagation(); // Событие не пойдёт выше
console.log('Клик на кнопку');
});
parent.addEventListener('click', (event) => {
console.log('На parent'); // Это НЕ выполнится
});
// Вывод: только "Клик на кнопку"
stopImmediatePropagation()
Этот метод не только останавливает всплытие, но и другие слушатели на текущем элементе:
button.addEventListener('click', (event) => {
event.stopImmediatePropagation();
console.log('Первый слушатель');
});
button.addEventListener('click', (event) => {
console.log('Второй слушатель'); // Это НЕ выполнится!
});
// Вывод: только "Первый слушатель"
preventDefault()
Отличается от stopPropagation(): не останавливает всплытие, а отменяет действие по умолчанию:
link.addEventListener('click', (event) => {
event.preventDefault(); // Не переходить по ссылке
console.log('Ссылка не откроется');
});
// Событие всё ещё всплывает!
parent.addEventListener('click', (event) => {
console.log('Событие всё ещё идёт вверх'); // Это ВЫПОЛНИТСЯ
});
Элементы, которые НЕ имеют всплытия
Не все события имеют всплытие:
// События БЕЗ всплытия:
- focus (но есть focusin с всплытием)
- blur (но есть focusout с всплытием)
- load / unload
- scroll
- resize
- reset
- submit
- mouseenter / mouseleave (но есть mouseover/mouseout с всплытием)
- mouseout / mouseover (разные!)
- media события (play, pause)
// Проверить, имеет ли событие всплытие:
const click = new MouseEvent('click');
console.log(click.bubbles); // true
const focus = new FocusEvent('focus');
console.log(focus.bubbles); // false
Делегирование событий (Event Delegation)
Всплытие позволяет реализовать мощный паттерн — делегирование:
<ul id="list">
<li>Элемент 1</li>
<li>Элемент 2</li>
<li>Элемент 3</li>
<!-- Динамически добавляются элементы -->
</ul>
// ❌ Неправильно: слушатель только на существующих элементах
const items = document.querySelectorAll('li');
items.forEach(item => {
item.addEventListener('click', handler);
});
// Новые элементы не будут работать!
// ✅ Правильно: слушатель на родителе
const list = document.getElementById('list');
list.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
console.log('Клик на:', event.target.textContent);
}
});
// Теперь новые элементы работают автоматически!
const newItem = document.createElement('li');
newItem.textContent = 'Элемент 4';
list.appendChild(newItem); // Клик на него всё равно сработает!
Реальный пример: обработка кликов по кнопкам
<div class="toolbar">
<button data-action="save">Сохранить</button>
<button data-action="delete">Удалить</button>
<button data-action="edit">Редактировать</button>
</div>
const toolbar = document.querySelector('.toolbar');
const actions = {
save: () => console.log('Сохранение...'),
delete: () => console.log('Удаление...'),
edit: () => console.log('Редактирование...')
};
toolbar.addEventListener('click', (event) => {
// Проверяем, кликнули ли на кнопку
if (event.target.tagName === 'BUTTON') {
const action = event.target.dataset.action;
const handler = actions[action];
if (handler) {
handler();
}
}
});
Производительность
Делегирование событий экономит память и ресурсы:
// ❌ Плохо: 1000 слушателей
const items = document.querySelectorAll('.item'); // 1000 элементов
items.forEach(item => {
item.addEventListener('click', handler); // 1000 слушателей!
});
// ✅ Хорошо: 1 слушатель
const container = document.querySelector('.container');
container.addEventListener('click', (event) => {
if (event.target.classList.contains('item')) {
handler(event);
}
});
Ключевые выводы
- Всплытие — процесс распространения события вверх по DOM
- Не все события имеют всплытие (focus, blur, load и т.д.)
event.stopPropagation()останавливает всплытиеevent.target— элемент, где произошло событиеevent.currentTarget— элемент с слушателем- Делегирование событий использует всплытие для эффективной обработки
- Делегирование экономит память и работает с динамическими элементами