DOM 이벤트 흐름과 Event Bubbling & Event Capturing

Haizel·2023년 5월 11일
1
post-thumbnail

기술 면접을 대비해 개념을 🍰 한입 크기로 잘라 정리합니다.
깃허브가 궁금하다면 놀러오세요!
👉 깃허브 보러가기 (Since 2023.05.10 ~ )

1. DOM 이벤트 흐름


표준 DOM 이벤트에서 정의한 이벤트 흐름의 3단계는 다음과 같습니다.

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

따라서 <td> 를 클릭하면

  1. 이벤트가 최상위 조상부터 시작해 아래로 전파되고(캡쳐링 단계)
  2. 이벤트가 타깃 요소로 도착해 실행된 후(타깃 단계)
  3. 다시 위로 전파(버블링 단계)됩니다.

2. 이벤트 버블링(Event Bubbling)


이벤트 버블링이란?

이벤트 버블링은 한 요소에 이벤트가 발생해 요소에 할당된 핸들러가 동작하면 → 이어 부모 요소의 핸들러가 동작하고 → 가장 최상단에 위치한 부모요소를 만날때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작하는 것을 의미합니다.

이벤트가 제일 깊은 곳에 있는 요소부터 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품, 즉 버블과 닮아 이벤트 버블링이라고 부릅니다.

이벤트 버블링 원리

  • 3개의 요소가 FORM > DIV > P 형태로 중첩된 구조가 있고, 각 요소에 핸들러가 할당되어 있다.
<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>


가장 안쪽의 <p> 요소를 클릭하면,

  1. <p>에 할당된 onclick 핸들러가 동작하고
  2. 상위요소 <div>에 할당된 onclick 핸들러가 동작합니다.
  3. 연이어 상위요소 <form>에 할당된 onclick 핸들러가 동작합니다.
  4. 이벤트 버블링은 document 객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작합니다.

💡 document 객체란?

  • DOM 트리 최상단 객체를 말합니다.

💡 모든 이벤트는 버블링 될까 ?

  • focus 이벤트와 같이 몇몇 이벤트를 제외한 대부분의 이벤트는 버블링된다.

3. 이벤트 버블링 중단하기


원하는 요소에서만 이벤트를 발생하게 하고 싶다면, event.stopPropagation()를 통해 버블링을 중단할 수 있습니다. 이를 사용하면 클릭한 타깃의 이벤만 발생하고 상위 요소로 이벤트가 전파되는 것을 막아줍니다.

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

💡 한 요소의 이벤트 핸들러가 두개라면?
한 요소의 특정 이벤트를 처리하는 핸들러가 여러개라면, event.stopPropagation()를 통해 하나의 핸들러의 버블링을 멈추더라도 나머지 핸들러는 여전히 동작합니다.

즉, event.stopPropagation() 는 상위로 일어나는 버블링은 막아주지만, 같은 요소에 할당된 다른 핸들러들이 동작하는 건 막지 못합니다.

따라서 상위로 일어나는 버블링을 중단하고, 같은 요소에 할당된 다른 핸들러의 동작도 막으려면 event.stopImmediatePropagation()를 사용하면 된다. 이 메서드를 사용하면 해당 요소에 할당된 이벤트를 처리하는 모든 핸들러의 동작이 중단된다.

이벤트 버블링 중단, 올바른가?

A. 버블링은 매우 유용하므로, 버블링을 꼭 멈춰야 하는 상황이 아니라면 버블링을 막지 않는 것이 좋다.

  • event.stopPropagation()을 사용한 영역은 ‘죽은 영역(Dead Zone)’이 되어버리기 때문입니다.
  • 불가피하게 버블링을 막아야한다면, 해당 메서드 대신 커스텀 이벤드 등을 사용해 이벤트 버블링을 통제하는 것이 권장됩니다.

4. event.target과 event.currentTarget


이벤트가 발생한 가장 안쪽 요소는 타깃(target)요소 라고 불리고, event.target을 사용해 접근할 수 있다.

  • event.target : 실제 이벤트가 시작된 ‘타깃’요소를 말하며, 버블링이 진행되어도 타깃 요소는 변하지 않습니다.
  • this(=event.currentTarget) : ‘현재’ 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조합니다.

위 구조에서 <p> 요소의 onClick 이벤트 핸들러를 동작시킨다면,

  • event.target : 실제 클릭한 요소인 <p> 요소
  • this(=event.currentTarget) : <form>요소에 있는 핸들러가 동작했기 때문에 <form>요소를 가리킨다.

5. 이벤트 캡처링(Event Capturing)


캡처링은 버블링과 반대로 최상위 태그에서 해당 태그를 찾아 내려가는 현상을 말합니다

이벤트 캡처링 원리

  • addEventListener 의 옵션 객체에 { capture: true } 또는 true 를 설정해 캡쳐링 구현할 수 있습니다.

<div class="DIV3">DIV3</div>를 클릭하면 최상위 부모요소부터 탐색해 내려오기 때문에 콘솔에 DIV1 → DIV2 → DIV3이 순서대로 찍히게 됩니다.

<body>
    <div class="DIV1">
      DIV1
      <div class="DIV2">
        DIV2
        <div class="DIV3">DIV3</div>
      </div>
    </div>
  </body>

const divs = document.querySelectorAll("div");

const clickEvent = (e) => {
  console.log(e.currentTarget.className);
};

divs.forEach((div) => {
  div.addEventListener("click", clickEvent, { capture: true });
});

5. 이벤트 버블링 한줄 정리


이벤트 버블링은 한 요소에 이벤트가 발생해 요소에 할당된 핸들러가 동작하면 → 이어 부모 요소의 핸들러가 동작하고, → 가장 최상단에 위치한 부모요소를 만날때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작하는 것을 의미합니다.

이벤트가 제일 깊은 곳에 있는 요소부터 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품, 즉 버블과 닮아 이벤트 버블링이라고 부릅니다.



📎 참고문서

profile
한입 크기로 베어먹는 개발지식 🍰

0개의 댓글