DOM 이벤트 전파는 조상에서 대상으로 내려오는 캡처 단계와 대상에서 조상으로 올라오는 버블 단계로 나뉩니다. 리스너 등록 때 캡처 옵션을 주면 내려오는 단계에서 실행됩니다.
데모는 중첩 버튼의 실제 클릭 리스너가 기록한 순서를 화살표에 재생합니다. 이벤트 위임과 전파 중단을 다룰 때 실행 단계를 구분해야 합니다.
언제 쓰나
부모와 자식에 클릭 리스너가 함께 있을 때 호출 순서를 확인합니다.
클릭 이벤트가 조상에서 대상까지 내려간 뒤 다시 조상으로 올라옵니다.
<div class="v eventflow"><header>EVENT PATH <span id="event-phase">capture</span></header><div class="stage event-stage"><div class="event-nest" id="root"><div id="parent"><button id="child">click target</button></div></div><div class="event-order"><span id="event0">root ↓</span><span id="event1">parent ↓</span><span id="event2">target</span><span id="event3">parent ↑</span><span id="event4">root ↑</span></div></div><div class="muted">capture ↓ · target · bubble ↑</div></div>.v{width:min(94vw,760px);height:min(88vh,320px);padding:clamp(9px,2.4vmin,18px);border:1px solid var(--line);border-radius:12px;background:var(--surface);font:500 clamp(12px,2.4vmin,16px)/1.3 var(--font-sans,system-ui,sans-serif);display:flex;flex-direction:column;gap:clamp(5px,1.4vmin,10px);overflow:hidden}.v header{display:flex;align-items:center;justify-content:space-between;gap:8px;color:var(--accent);font-weight:700}.v header span{color:var(--muted);font-weight:500}.v .stage{flex:1;min-height:0;position:relative}.v .muted{color:var(--muted)}.v .active{background:color-mix(in srgb,var(--accent) 18%,var(--surface));border-color:var(--accent)!important;color:var(--fg)}.v button{font:inherit;color:var(--fg);background:var(--bg);border:1px solid var(--line);border-radius:7px;padding:5px 8px;cursor:pointer}.event-stage{display:flex;align-items:center;justify-content:center;gap:9px}.event-nest{width:55%;height:85%;border:2px solid var(--accent-2);border-radius:9px;padding:8px;display:grid;place-items:center;background:color-mix(in srgb,var(--accent-2) 10%,var(--surface))}.event-nest #parent{width:82%;height:75%;border:2px solid var(--accent);border-radius:8px;display:grid;place-items:center;background:var(--surface)}.event-nest button{font-size:clamp(12px,2.2vmin,13px);white-space:nowrap}.event-order{display:flex;flex-direction:column;gap:2px}.event-order span{font-size:clamp(12px,2vmin,12px);color:var(--muted);padding:1px 4px;border-radius:4px}.event-order span.on{color:var(--accent);background:color-mix(in srgb,var(--accent) 15%,var(--surface));font-weight:700}const root=document.getElementById("root"),parent=document.getElementById("parent"),child=document.getElementById("child"),order=[];root.addEventListener("click",()=>order.push("root down"),true);parent.addEventListener("click",()=>order.push("parent down"),true);child.addEventListener("click",()=>order.push("target"));parent.addEventListener("click",()=>order.push("parent up"));root.addEventListener("click",()=>order.push("root up"));let step=0;function show(){if(step===0){order.length=0;child.click()}for(let j=0;j<5;j++)document.getElementById("event"+j).classList.toggle("on",j===step);document.getElementById("event-phase").textContent=step<2?"capture":step===2?"target":"bubble";step=(step+1)%order.length}show();setInterval(show,450);child.addEventListener("pointerdown",()=>{step=0})DOM 이벤트 전파는 조상에서 대상으로 내려오는 캡처 단계와 대상에서 조상으로 올라오는 버블 단계로 나뉩니다. 리스너 등록 때 캡처 옵션을 주면 내려오는 단계에서 실행됩니다.
데모는 중첩 버튼의 실제 클릭 리스너가 기록한 순서를 화살표에 재생합니다. 이벤트 위임과 전파 중단을 다룰 때 실행 단계를 구분해야 합니다.
부모와 자식에 클릭 리스너가 함께 있을 때 호출 순서를 확인합니다.