안녕하세요 메이토입니다 🍅
오늘은 CS 스터디 중 맛있게 공부했던 주제인 이벤트 전파와 위임에 대해 알아보려고 합니다 !
이벤트 전파 흐름
이벤트 전파에는 아래와 같은 3가지 흐름으로 구성됩니다 !
(1) 캡처링 단계 : 상위요소에서 하위요소로 이벤트가 전파되는 단계
- window → document → <html> → <body> → … → 타깃 요소
(2) 타깃 단계 : 실제 타깃요소에 이벤트가 전달되는 단계
(3) 버블링 단계 : 하위요소에서 상위요소로 이벤트가 전파되는 단계
이벤트 캡처링
- 한 요소에 이벤트 발생 → 그 요소의 자식 요소의 이벤트까지 전파되는 현상
이벤트 감지 시점 Default = 버블링이기 때문에 캡처링 단계에서 이벤트 핸들러를 실행시키기 위해서는 아래와 같이 추가적으로 설정을 해줘야 합니다 !
EventTarget.addEventListener('eventType',(e) => {...}, true)
예시 코드
<div id="ancestor">
<div id="parent">
<div id="child"/>
</div>
</div>
ancestor.addEventListener("click", (e) => {
console.log('ancestor clicked');
}, true)
parent.addEventListener("click", (e) => {
console.log('parent clicked');
}, true)
child.addEventListener("click", (e) => {
console.log('child clicked');
}, true)
❓여기서 child 요소를 클릭하면 어떻게 이벤트가 발생하고, 콘솔에 어떤 순서로 값이 찍힐까?
- 이벤트 핸들러가 캡처링 단계 (이벤트 전파 중 첫 단계) 에 실행되고 있으니 ancestor → parent → child 순으로 콘솔이 찍힘
- 버블링되는 순서가 바뀌거나 그런것이 아니라 🚀<캡처링 옵션은 이벤트 핸들러가 실행되는 시점이 결정되는 것>
이벤트 버블링
- 한 요소에 이벤트 발생 → 그 요소의 부모 요소의 이벤트까지 전파되는 현상
거의 모든 이벤트는 버블링된다 ! (focus 처럼 안되는 경우도 있음)
❓ Why? focus는 안되나요?
- 브라우저 설계 상 focus는 타겟 요소 자체에만 의미가 있는 이벤트
- 포커스를 가진 요소만 실제로 ‘활성화’ 상태
- 그래서 기본적으로 focus와 blur는 버블링되지 않음
<div id="ancestor">
<div id="parent">
<div id="child"></div>
</div>
</div>
ancestor.addEventListener("click", (e) => {
console.log('ancestor clicked');
})
parent.addEventListener("click", (e) => {
console.log('parent clicked');
})
child.addEventListener("click", (e) => {
console.log('child clicked');
})
❓여기서 child 요소를 클릭하면 어떻게 이벤트가 발생하고, 콘솔에 어떤 순서로 값이 찍힐까?
- 이벤트 핸들러가 버블링 단계에 실행되고 있으니 child’→ ‘parent’→’ancestor순으로 콘솔이 찍힘
⚠️ 이벤트 전파 방지
e.stopPropagation() - 이벤트 전파 방지 (캡처링, 버블링 단계 모두 전파 막을 수 있음)
🤔 [참고] 이벤트의 기본 동작을 막는 건 e.preventDefault()
ex) <form> 제출 막기, <a> 링크 이동 막기 등
이벤트 위임
- 요소마다 핸들러를 할당하지 않고 요소의 공통 조상에 이벤트 핸들러를 하나만 할당해서 여러 요소를 한꺼번에 다루는 것
<div id="outer" style="padding:20px; border:2px solid blue;">
Outer DIV
<div id="inner" style="margin:20px; padding:20px; border:2px solid green;">
Inner DIV
<div id="deep" style="margin:20px; padding:20px; border:2px solid red;">
Deep DIV
</div>
</div>
</div>
const outer = document.getElementById('outer');
outer.onclick = function(event) {
console.log("event.target:", event.target.id);
console.log("event.currentTarget:", event.currentTarget.id);
// 항상 outer에서 실행됨 (리스너가 달린 곳)
// 하지만 target은 클릭된 실제 요소
if (event.target.id !== 'inner') return;
highlight(event.target);
};
function highlight(element) {
element.style.backgroundColor = 'yellow';
}


왼쪽 : Deep Div 영역 (빨간 테두리) 내부를 클릭 했을 때
오른쪽: Deep Div를 제외한 Inner Div (초록 테두리 - 빨간 테두리) 내부를 클릭했을 때
우리가 의도한 동작 - > Deep 은 Inner 자식 요소이니 Deep을 클릭해도 Inner가 하이라이팅 되어야 하는데 ,,
🔥 문제
그래서 현재 코드에서 아래와 같은 조건 때문에
if (event.target.id !== 'inner') return;
- inner 영역을 직접 클릭할 때만 하이라이팅 (내부의 deep을 클릭하면 동작 ❌)
💡해결
outer.onclick = function (event) {
const inner = event.target.closest("#inner");
if (!inner || !outer.contains(inner)) return;
highlight(inner);
};
→ closest를 쓰면 inner 내부 어디를 클릭해도 (deep 포함) inner가 선택되어 highlight가 정상적으로 동작
동작 원리
- 이벤트 버블링(Event Bubbling)을 활용
- 이벤트가 실제 발생한 요소(target) → 부모 요소로 전파(bubble)
- 부모 요소에서 이벤트를 잡고, event.target이나 closest()로 실제 요소 판별
이렇게 이벤트 위임을 통해 자식 요소가 많은데 각각 리스너를 달아야 할 경우, 메모리 사용을 줄일 수 있고 추후 동적으로 추가되는 자식 요소에도 이벤트 처리가 가능하다는 장점이 있습니다 ! 바로 이 내용을 통해 저희 ' 아인슈타임 ' 에도 렌더링을 줄이기 위한 리팩토링 방법으로 이벤트 위임을 활용해보려고 합니다 !
다음 글 예고 ,, 프로젝트에 이벤트 위임 적용하기 🍀
'언어 영역' 카테고리의 다른 글
| [JS] 한글을 입력하면 이벤트가 중복발생된다 ..? (1) | 2025.03.23 |
|---|