영원히 흘러가는 강
브라우저 이벤트는 어떤 순서로 실행되고, 언제 어떻게 막아야 할까? 본문
프론트엔드에서 이벤트는 사용자와 애플리케이션을 연결하는 가장 중요한 요소 중 하나다.
하지만 이벤트를 명확한 기준 없이 남발하거나 무차별적으로 사용하기 시작하면, 당연히 코드는 산으로 갈것이다.
예를 들어 이벤트 전파 구조를 충분히 이해하지 못한 채 문제가 생길 때마다 전파를 막아버리면, 원인은 파악하지 못한 채 증상만 해결하는 코드가 쌓이게 된다.
아래에서는 이벤트 실행 순서 기반으로 이벤트를 잘 사용하는 방법에 대해 작성해보려한다.
1. 이벤트 실행 순서
브라우저에서는 이벤트를 DOM트리를 따라 3단계로 전달하여 처리한다.
캡처링 ➡ 타겟 ➡ 버블링

1.1 캡처링 단계
이벤트는 window에서 시작해서 실제 이벤트가 발생한 요소까지 위 -> 아래 로 내려온다.
캡처링 단계에서는 이벤트 리스너가 실행되지 않는다.
하지만 addEventListener의 세번째 인자를 true로 설정하면 캡처링 단계에서도 이벤트를 감지할수있다고 한다.
document.addEventListener(
"click",
() => {
console.log("캡처링 단계");
},
true
);
1.2 타겟 단계
- 실제로 발생한 요소에 도달한 시점
- event.target이 명확하게 결정되는 시점
- 현 단계에서는 캡처링 리스너, 버블링 리스너 모두 실행될 수 있다.
1.3 버블링 단계
이벤트는 타겟 요소에서 실행된 뒤 다시 아래 - > 위 방향으로 올라간다.
* 버블링 단계가 중요한 이유 : 이벤트 위임
이벤트 위임의 장점은 아래와 같다.
- 여러 자식 요소에 각각 이벤트를 등록하지 않아도, 상위 요소 하나에서 이벤트 처리 가능
- 동적 ui에 자연스럽게 대응 가능하다. (재등록 불필요)
- 이벤트 흐름을 한 지점에서 관리 가능
- 코드 간결 및 메모리 사용 감소
2. 이벤트 제어: 언제 무엇을 막아야 할까?
stopPropagation / preventDefault 두개를 혼동 많이 하는데
stopPropagation = 이벤트 전파 중단
preventDefault = 브라우저 동작 중단
이벤트 전파 중단 = stopPropagation()
부모로의 이벤트 전파를 막는 방법
대표적인 상황
- 모달 내부 클릭이 배경 클릭 핸들러를 트리거할때
- 드롭다운 내부 클릭이 외부 클릭 감지 로직에 걸릴때
- 특정 컴포넌트가 독립적이어야할때
<div class="backdrop">
<div class="modal">닫히면 안 되는 영역</div>
</div>
// script 부분
const backdrop = document.querySelector(".backdrop");
const modal = document.querySelector(".modal");
backdrop.addEventListener("click", () => {
closeModal();
});
modal.addEventListener("click", (e) => {
e.stopPropagation();
});
브라우저 기본 동작 방지 = preventDefault()
대표적인 상황
- 링크 이동 , form submit 등 기본 동작 방지 시
<a href="/delete" class="deleteBtn">삭제</a>
// script 부분
const deleteBtn = document.querySelector(".deleteBtn");
deleteBtn.addEventListener("click", (e) => {
e.preventDefault();
openConfirmModal();
});
이벤트 역시 설계의 영향을 크게 받는 영역이라는 점을 느꼈고,
이벤트를 잘 막는거도 중요하지만 애초에 막지 않는 구조가 더 중요하다고 생각된다.
다음 포스트에서는 같지만 다른 React에서의 이벤트를 다뤄보려한다.