Как отловить событие на погружение?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Event Bubbling и фаза погружения (Capturing Phase)
Вопрос о погружении относится к фазам распространения событий в DOM. В браузере события проходят три фазы: погружение (capturing), цель (target) и всплытие (bubbling).
Три фазы события
Когда вы кликаете на элемент, событие проходит три этапа:
1. CAPTURING PHASE (погружение) — событие идёт вниз от window к целевому элементу
2. TARGET PHASE (целевая фаза) — событие на самом элементе
3. BUBBLING PHASE (всплытие) — событие идёт вверх от элемента к window
По умолчанию обработчики вешаются на фазу всплытия (bubbling).
Отловить событие на погружение (Capturing)
Для перехвата события в фазе погружения используй третий параметр в addEventListener:
// Запуск на фазе всплытия (по умолчанию)
element.addEventListener("click", handler); // bubbling phase
element.addEventListener("click", handler, false); // явно bubbling
// Запуск на фазе погружения
element.addEventListener("click", handler, true); // capturing phase
element.addEventListener("click", handler, { capture: true }); // объект опций
Практический пример
const parent = document.getElementById("parent");
const child = document.getElementById("child");
// Фаза погружения - срабатывает ПЕРВОЙ
parent.addEventListener("click", (e) => {
console.log("Родитель - ПОГРУЖЕНИЕ (capturing)");
}, true); // true = capturing
// Фаза всплытия - срабатывает ВТОРОЙ
parent.addEventListener("click", (e) => {
console.log("Родитель - ВСПЛЫТИЕ (bubbling)");
}, false); // false = bubbling (по умолчанию)
// Клик на child
child.addEventListener("click", (e) => {
console.log("Ребёнок - нажата");
});
// HTML:
// <div id="parent">
// <div id="child">Click me</div>
// </div>
// Вывод при клике на child:
// 1. Родитель - ПОГРУЖЕНИЕ (capturing)
// 2. Ребёнок - нажата
// 3. Родитель - ВСПЛЫТИЕ (bubbling)
Когда использовать capturing
Фаза погружения полезна, когда нужно перехватить событие ДО того, как оно достигнет целевого элемента:
// Пример 1: Глобальный обработчик на document с capturing
document.addEventListener("click", (e) => {
console.log("Клик произошёл на:", e.target);
}, true); // capturing - срабатывает для всех кликов в документе
// Пример 2: Перехват события перед обработкой
const form = document.getElementById("form");
form.addEventListener("submit", (e) => {
console.log("Форма отправляется (capturing)");
// Можно отменить распространение
e.stopPropagation();
}, true);
// Внутри формы есть input, и его обработчик не сработает
const input = document.getElementById("input");
input.addEventListener("submit", () => {
console.log("Это не сработает из-за stopPropagation");
});
Разница между capturing и bubbling
// HTML
// <div id="outer">
// <div id="inner">
// <button id="btn">Click</button>
// </div>
// </div>
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");
const btn = document.getElementById("btn");
// --- BUBBLING PHASE (по умолчанию) ---
// Порядок: btn -> inner -> outer
btn.addEventListener("click", () => console.log("btn - bubble"));
inner.addEventListener("click", () => console.log("inner - bubble"));
outer.addEventListener("click", () => console.log("outer - bubble"));
// Вывод: btn - bubble, inner - bubble, outer - bubble
// --- CAPTURING PHASE ---
// Порядок: outer -> inner -> btn
btn.addEventListener("click", () => console.log("btn - capture"), true);
inner.addEventListener("click", () => console.log("inner - capture"), true);
outer.addEventListener("click", () => console.log("outer - capture"), true);
// Вывод: outer - capture, inner - capture, btn - capture
Остановка распространения
Чтобы остановить распространение события на других фазах:
element.addEventListener("click", (event) => {
// Остановить распространение
event.stopPropagation(); // событие не пойдёт выше
// Остановить все обработчики для этого события
event.stopImmediatePropagation();
// Отменить действие по умолчанию (например, переход по ссылке)
event.preventDefault();
});
React и фазы событий
В React используется система делегирования, события вешаются на корневой элемент. Для capturing в React нужно использовать нативные события:
function Component() {
useEffect(() => {
// React обработчики используют bubbling
const handleClick = () => console.log("Bubbling");
element.addEventListener("click", handleClick); // bubbling
// Для capturing нужен нативный addEventListener
element.addEventListener("click", handleClick, { capture: true });
return () => {
element.removeEventListener("click", handleClick);
element.removeEventListener("click", handleClick, { capture: true });
};
}, []);
return <div ref={ref}>Content</div>;
}
Итого
Для отловки события на погружение (capturing phase):
- Используй третий параметр — addEventListener(event, handler, true) или { capture: true }
- Фаза погружения срабатывает первой — от родителя к элементу
- Фаза всплытия срабатывает второй — от элемента к родителю
- stopPropagation() останавливает распространение события
- В React используй нативный addEventListener для capturing
Capturing используется редко, обычно работают со всплытием (bubbling).