버블링과 캡처링

JTechBlog·2024년 3월 21일
post-thumbnail

버블링

한 요소에 이벤트가 발생할 경우,
이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작한다.

이처럼 가장 최상단의 조상 요소를 만날 때까지
이 과정이 반복되면서 요소 각각에 할당된 핸들러가
동작하는 현상을 버블링이라 한다.

이벤트가 가장 깊은 곳의 요소에서 시작되어
부모 요소를 거슬러 올라가며 발생하는 모습이
물속 거품과 유사하여 생긴 이름이다.

아래와 같은 코드가 있을때 가장 안쪽의 p 요소를 클릭하면,

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form onclick="alert('form')">
  FORM
  <div onclick="alert('div')">
    DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>
  1. <p> 에 할당된 onclick 핸들러 동작,
  2. 바깥의 <div>에 할당된 핸들러 동작,
  3. 그 바깥의 <form>에 할당된 핸들러가 동작,
  4. document 객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작한다.

여기에서 이벤트가 발생한 가장 안쪽의 요소를
타겟(target) 이라 부르는데, event.target 으로 접근 가능하다.

버블링 중단하는 방법

이벤트 버블링은 타겟 이벤트에서 시작해서 html요소를 거쳐
document 객체를 만날 때까지 각 노드에서 모두 발생하는데,
몇몇 이벤트는 window 객체까지 거슬러 올라가기도 한다.

이런 경우에, event.stopPropagation() 사용하여 버블링을 방지할 수 있다.
만약, 요소에 할당된 다른 핸들러의 동작도 막고 싶다면 event.stopImmediatePropagation()을 사용한다.

<body onclick="alert(`버블링은 여기까지 도달하지 못합니다.`)">
  <button onclick="event.stopPropagation()">클릭해 주세요.</button>
</body>


캡처링

표준 DOM 이벤트에서 정의한 이벤트 흐름엔 아래와 같이 3가지 단계가 있다.

  1. 캡처링 단계 – 이벤트가 하위 요소로 전파되는 단계
  2. 타겟 단계 – 이벤트가 실제 타깃 요소에 전달되는 단계
  3. 버블링 단계 – 이벤트가 상위 요소로 전파되는 단계

onEvent 프로퍼티나 HTML 속성, addEventListener(event, handler)를
이용해 할당된 핸들러는 캡처링에 대해 전혀 알 수 없다. 즉, 이 핸들러들은
두 번째 혹은 세 번째 단계의 이벤트 흐름(타겟 단계와 버블링 단계) 에서만 동작하는데,

만약 캡처링 단계에서 이벤트를 잡아내려면
아래와 같이 addEventListener의 capture 옵션을 true로 설정하면 된다.

elem.addEventListener(..., {capture: true})

이벤트 핸들러가 캡처링 단계의 이벤트를 캐치하도록 설정되어 있다면,
이벤트 핸들러는 window 에서 시작해서 event target 방향으로 전파되는 이벤트 객체를 캐치하고,
이벤트를 발생시킨 event target 과 이벤트 핸들러가 바인딩된 current target 이 같은 DOM 요소라면
이벤트 핸들러는 target 단계의 이벤트 객체를 캐치한다.

캡처링은 이벤트를 더 먼저 감지하고 처리하기 위해 사용되는데,
주로 다음과 같은 목적에서 활용한다.

  1. 이벤트 우선 제어
    • 특정 요소보다 상위 요소가 먼저 이벤트를 가로채고 처리하고 싶을 때 유용
    • 예를 들어, 하위 요소의 동작을 미리 차단하거나, 로깅/추적 용도로 사용
document.body.addEventListener(
  'click',
  () => console.log('캡처링: body 클릭 감지'),
  true // capture: true 설정
);
  1. 보안 또는 무결성 제어
    • 특정 사용자 동작을 일정 조건에서 제한하거나 허용 여부를 선제적으로 판단.
    • 예: 특정 버튼 클릭을 조건에 따라 막고 싶을 때, 버튼보다 상위 요소에서 먼저 확인.

  2. 이벤트 흐름의 디버깅 및 분석
    • 어떤 경로로 이벤트가 전파되는지 파악할 때 캡처링 단계부터 확인이 가능해서 디버깅에 도움이 됨.

  3. 서로 다른 버블링 이벤트 제어
    • 동일한 요소에 여러 이벤트가 버블링될 때 캡처링을 이용해 처리 우선순위를 조절할 수 있다.

요약하면, 각 핸들러는 아래와 같은 event 객체의 프로퍼티에 접근할 수 있다.

  • event.target – 이벤트가 발생한 가장 안쪽의 요소
  • event.currentTarget (=this) – 이벤트를 핸들링 하는 현재 요소 (핸들러가 실제 할당된 요소)
  • event.eventPhase – 현재 이벤트 흐름 단계(캡처링=1, 타겟=2, 버블링=3)

핸들러에서 event.stopPropagation()을 사용해 이벤트 버블링을 멈출 수 있다.
다만, 이 방법은 추천하지 않는데, 왜냐하면 지금은 상위 요소에서 이벤트가 어떻게 쓰일지 확실치 않더라도,
추후에 버블링이 필요한 경우가 생기기 때문이다.

profile
웹/앱 개발 정보를 공유합니다.

0개의 댓글