프론트엔드 개발자 - 자곰

Front-end/Javascript

이벤트 버블링과 이벤트 캡처링

자곰 2023. 7. 26. 22:49

이벤트 버블링과 이벤트 캡처링은 자바스크립트의 이벤트 전파 방식에 대해 중요한 개념입니다. 이 두 가지는 이벤트가 DOM 요소에서 상위 요소로 전파되는 방향을 나타내며, 이를 이해하고 활용하면 효율적인 이벤트 처리와 이벤트 위임을 구현할 수 있습니다.

이벤트 버블링 (Event Bubbling)

이벤트 버블링은 이벤트가 발생한 요소에서 시작하여, 상위 요소로 전파되는 방식입니다. 즉, 자식 요소에서 발생한 이벤트가 부모 요소로 전파됩니다. 예를 들어, 클릭 이벤트가 버튼에서 발생하면, 버튼 -> 부모요소 -> 부모요소의 부모요소 순으로 이벤트가 전파됩니다.

이벤트 버블링

💡 ⚠️거의 모든 이벤트는 버블링 됩니다.

키워드는 ‘거의’ 입니다. focus 이벤트와 같이 버블링 되지 않는 이벤트도 있습니다. 버블링 되지 않는 이벤트의 종류에 대해선 조금 후에 알아보겠습니다. 몇몇 이벤트를 제외하곤 대부분의 이벤트는 버블링 됩니다.

<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>

코드로 설명해보겠습니다. <p>를 클릭하면 순서대로 다음과 같은 일이 벌어집니다. 

  1. <p>에 할당된 onclick 핸들러가 동작합니다.
  2. 바깥의 <div>에 할당된 핸들러가 동작합니다.
  3. 그 바깥의 <form>에 할당된 핸들러가 동작합니다.
  4. document 객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작합니다.

이런 동작 방식 때문에 <p> 요소를 클릭하면 p → div → form 순서로 3개의 얼럿 창이 뜨는것이죠.

이런 흐름을 '이벤트 버블링’이라고 부릅니다. 이벤트가 제일 깊은 곳에 있는 요소에서 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품(bubble)과 닮았기 때문입니다.

 

이벤트 캡처링 (Capturing)

이벤트엔 버블링 이외에도 ‘캡처링(capturing)’ 이라는 흐름이 존재합니다. 실제 코드에서 자주 쓰이진 않지만, 종종 유용한 경우가 있으므로 알아봅시다.

이벤트 흐름엔 3가지 단계가 있습니다.

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

이벤트 전파 그림

위 그림에서 1,2,3 단계를 설명해주고 있습니다.

<td> 를 클릭하면 이벤트가 최상위 조상에서 시작해 아래로 전파되고 (캡처링), 이벤트가 타깃 요소에 도착 후 실행(타킷 단계), 다시 위로 전파됩니다(버블링).

캡처링 단계를 이용해야 하는 경우는 흔치 않기 때문에, 이전까진 주로 버블링만 설명했습니다. 캡처링에 관한 코드를 발견하는 일은 거의 없을 겁니다.

elem.addEventListener(..., {capture: true})
// 아니면, 아래 같이 {capture: true} 대신, true를 써줘도 됩니다.
elem.addEventListener(..., true)

capture 옵션은 두 가지 값을 가질 수 있습니다.

  • false이면(default 값) 핸들러는 버블링 단계에서 동작합니다.
  • true이면 핸들러는 캡처링 단계에서 동작합니다.

마무리

이벤트가 발생하면 해당 이벤트는 DOM 트리를 따라 이벤트 타깃 요소까지 전파됩니다. 이 과정에서 addEventListener로 할당한 핸들러들이 동작하며, 캡처링 단계와 버블링 단계로 나뉘어집니다.

  1. 캡처링 단계 (Capture Phase): 이벤트는 최상위 노드(document)에서 시작하여 DOM 트리를 따라 아래로 내려오면서 addEventListener(..., true)로 할당한 핸들러들이 동작합니다. 캡처링 단계는 일반적으로 사용되지 않습니다.
  2. 타깃 단계 (Target Phase): 이벤트가 발생한 가장 안쪽 요소(event.target)에 설정된 핸들러가 호출됩니다. event.target은 이벤트가 발생한 요소를 가리킵니다.
  3. 버블링 단계 (Bubble Phase): 이벤트는 다시 최상위 노드(document) 방향으로 올라가면서 각 요소에 on<event>로 할당한 핸들러와 addEventListener(..., false) 또는 {capture: false}로 할당한 핸들러를 동작시킵니다. 이 때, 캡처링 단계에서 할당한 핸들러는 호출되지 않습니다.

또한, 이벤트 핸들러 내에서는 event 객체를 통해 다양한 정보에 접근할 수 있습니다:

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

이벤트 핸들러 내에서 event.stopPropagation()을 사용하면 이벤트 버블링을 멈출 수 있으나, 이 방법은 권장되지 않습니다. 버블링이 필요한 경우를 위해 항상 이벤트 버블링을 유지하는 것이 좋습니다.

버블링과 캡처링은 이벤트 위임(event delegation)의 기반이 됩니다. 이벤트 위임은 강력한 이벤트 핸들링 패턴으로, 다수의 요소에 개별적으로 이벤트 핸들러를 할당하는 대신, 공통된 부모 요소에 이벤트 핸들러를 할당하여 관리하는 방식입니다. 이를 통해 메모리 사용과 성능을 개선할 수 있습니다.

이제 이벤트 전파 방식을 배웠으니 다음에는 이벤트 위엠에 대해서 다루겠습니다.

'Front-end > Javascript' 카테고리의 다른 글

Promise(2) - 프라미스 체이닝  (0) 2023.08.02
Callback  (0) 2023.08.01
이벤트 위임  (0) 2023.07.28
자바스크립트 엔진  (0) 2023.07.23
자바스크립트의 프로토타입에 대한 고찰  (0) 2022.02.06