
HTML과 CSS로 간단한 구조를 만들고, JavaScript로 각 요소에 클릭 이벤트 핸들러를 등록했을 때 예상하지 못한 동작이 발생할 수 있다. 예를 들어:
위와 같은 현상의 원인을 이벤트 버블링이라고 부른다.
이벤트 버블링은 특정 요소에서 이벤트가 발생했을 때 해당 이벤트가 부모 요소로 전달되며 최상위 요소까지 전파되는 동작을 의미한다. 이 동작은 이벤트가 발생한 자식 요소부터 부모 요소로 "거품처럼" 올라간다고 해서 버블링(Bubbling)이라는 이름이 붙었다.
window 객체에 도달.버블링은 물속에서 올라오는 거품과 비슷한 동작 원리를 가지고 있어 이러한 이름이 붙었다.
<div id="content">
<div id="list">
<div id="item">Item</div>
</div>
</div>
// 각 요소에 이벤트 핸들러 등록
const content = document.querySelector('#content');
const list = document.querySelector('#list');
const item = document.querySelector('#item');
content.addEventListener('click', () => console.log('Content 클릭!'));
list.addEventListener('click', () => console.log('List 클릭!'));
item.addEventListener('click', () => console.log('Item 클릭!'));
출력 결과:
item 클릭 시: Item 클릭 → List 클릭 → Content 클릭list 클릭 시: List 클릭 → Content 클릭content 클릭 시: Content 클릭이벤트 버블링에 의해 item에서 시작된 이벤트가 부모인 list, 그리고 그 상위인 content로 전파되며 핸들러가 실행된다.
이벤트 핸들러에 전달되는 이벤트 객체는 이벤트와 관련된 다양한 정보를 담고 있다. 이를 활용해 이벤트의 원래 발생 요소, 핸들러가 등록된 요소 등을 확인할 수 있다.
targetcurrentTargetitem.addEventListener('click', (event) => {
console.log('Target:', event.target); // 클릭된 실제 요소
console.log('Current Target:', event.currentTarget); // 현재 실행 중인 핸들러가 등록된 요소
});
출력 결과
event.target: #itemevent.currentTarget: #item부모 요소의 핸들러에서도 target은 변하지 않고 최초의 이벤트 발생 요소를 가리킨다.
특정 상황에서 버블링을 멈추고 싶다면 event.stopPropagation() 메서드를 활용한다.
item.addEventListener('click', (event) => {
console.log('Item 클릭!');
event.stopPropagation(); // 버블링 중단
});
list.addEventListener('click', () => console.log('List 클릭!'));
content.addEventListener('click', () => console.log('Content 클릭!'));
출력 결과
Item을 클릭했을 때:
Item 클릭!event.stopPropagation()에 의해 이벤트가 부모 요소로 전파되지 않는다.
주의점
버블링을 중단하면 부모 요소에서 처리해야 할 이벤트가 실행되지 않을 수 있다. 예를 들어, 전체 페이지에서 특정 동작을 감지하는 이벤트 핸들러가 있다면, 버블링 중단 구간에서는 의도한 동작이 실행되지 않을 수 있다.
document.body.addEventListener('click', () => console.log('Body 클릭!'));
item.addEventListener('click', (event) => {
console.log('Item 클릭!');
event.stopPropagation();
});
위 코드에서 item을 클릭하면 body에 등록된 핸들러는 동작하지 않는다.
event.target과 event.currentTarget: 이벤트 발생 요소와 핸들러가 등록된 요소를 구분.event.stopPropagation()으로 이벤트 전파를 멈출 수 있다.