
브라우저에서 버튼을 클릭하거나 키보드를 입력하면,
그 이벤트는 단지 한 요소에서만 처리되는 것이 아니다.
DOM 트리 전체를 타고 흐르며, 캡처링 → 타겟 → 버블링이라는 3단계 과정을 거친다.
이 구조를 정확히 이해하는 것은
이벤트 위임, 동적 요소 처리, stopPropagation의 쓰임새를 이해하는 데 필수적이다.
이벤트 전파(Event Propagation)란,
브라우저가 특정 요소에서 이벤트가 발생했을 때,
그 이벤트가 DOM 트리를 따라 상위 또는 하위 요소로 이동하면서 전파되는 흐름을 말한다.
이벤트 전파는 총 3단계로 구성된다:
이벤트가 DOM 최상위 요소(document)에서부터 시작해
이벤트가 실제 발생한 타겟 요소까지 내려오는 과정이다.
<body>
<div id="outer">
<button id="inner">Click</button>
</div>
</body>
button을 클릭하면, 이벤트는 다음 순서로 "내려간다"
document -> html -> body -> div#outer -> button#inner
이때 각 단계에서
{capture: true}옵션이 걸려 있는 리스너만 실행된다.
document.body.addEventListener(
"click",
() => console.log("캡쳐링: body"),
{capture: true}
);
이벤트가 실제로 발생한 요소(이벤트 타겟)에 도달한 시점이다.
즉, 사용자가 클릭한 그 요소에서 click,input,change 등 이벤트가 실제 트리거된다.
이 시점에서는 캡처링/버블링 여부와 상관없이 항상 실행된다.
document.getElementById("inner").addEventListener("click", () => {
console.log("타깃 단계");
})
타겟 요소에서 이벤트가 끝나면,
이제는 반대로 DOM 트리를 상위 요소로 올라가면서 전파된다.
button#inner -> div#outer -> body -> html -> document
document.body.addEventListener("click", () => {
console.log("버블링: body");
}); // capture: false 가 기본값
<div id="outer">
<button id="inner">Click me</button>
</div>
document.getElementById("outer").addEventListener(
"click",
() => console.log("캡처링 - outer"),
{ capture: true }
);
document.getElementById("outer").addEventListener("click", () =>
console.log("버블링 - outer")
);
document.getElementById("inner").addEventListener("click", () =>
console.log("타겟 - inner")
);
캡처링 - outer
타겟 - inner
버블링 - outer
element.addEventListener("click", (e) => {
e.stopPropagation();
})
e.stopPropagation() -> 이벤트가 이후 단계로 전달되지 않게 함stopImediatePropagation() -> 현재 요소의 다른 리스너도 실행하지 않음사용 예:
이벤트 전파를 이용하면, 하나의 부모 요소에 리스너를 걸고
자식 요소의 이벤트까지 처리하는 방식, 즉 이벤트 위임을 구현할 수 있다.
document.getElementById("list").addEventListener("click", (e) => {
if (e.target.matches("li") {
console.log(`클릭한 항목: ${e.target.textContent}`);
})
})
이벤트 위임은 동적 요소 처리, 성능 최적화, 메모리 절약 등에 매우 효과적이다.
addEventListener의 세 번째 인자 { capture: true }를 통해 캡처링 리스너 등록이 가능하다.stopPropagation()을 통해 중간에서 이벤트 흐름을 끊을 수 있다.