본문 바로가기

CS/Javascript

이벤트 버블링, 캡쳐링 및 이벤트 위임

반응형

예전에 모달을 만들 때, 모달의 'x'버튼을 누르면 모달이 꺼지는 이벤트가 모달을 눌렀을 때에도 적용이 되어 이것이 이벤트 버블링 현상에 의한 것이라는 것을 처음 알게 되었다. 오늘은 이벤트 버블링과 캡쳐링, 그리고 이벤트 위임에 대해 간단히 정리해보자. 

이벤트 흐름이란?

HTML 요소가 다른 요소의 내부에 중첩되어 있을 때 자식 요소를 클릭하면 부모 요소를 클릭한 된다. 이처럼 이벤트는 흐름을 가지고 있으며, 이것을 이벤트 흐름이라고 부른다. 이벤트 흐름에는 두가지 방식인 이벤트 버블링과 캡쳐링이 있다.

www.howdy-mj.me

DOM이 겹쳐져 있을 경우 이벤트 시발점과 관련된 모든 요소들이 이벤트에 탑승하게 된다.

  • currnet target: 이벤트의 현재 주인
  • target: 이벤트의 시발점

예시를 살펴보자. 다음과 같이 div 태그가 하나 있고 그 위에는 body, 그 위에는 html, 그 위에는 브라우저가 있다. div가 클릭되었을 때 단순히 div만 영향을 받는게 아니라 위에 있는 부모 요소들까지 전부 영향을 받는다. 그런데 만약 부모 요소들도 각자의 이벤트를 가지고 있으면 어떻게 될까? 이벤트가 뒤죽박죽 섞일까?


관련된 엘리멘트들도 각각 이벤트를 가지고 있을 경우, 순차적으로 이벤트가 실행되어야 한다. 이를 처리하기 위해 브라우저는 이벤트 플로우를 가진다.

html가 루트라면 밑에는 브라우저가 있다.

  • 이벤트 플로우는 브라우저와 가장 가까운 것부터 실행되며 자식 엘리멘트로 내려가는 것을 'capture phase'이라고 한다.
  • target에서 이벤트가 실행되는 것을 'target phase'라고 한다.
  • 이후에 부모 엘리먼트를 향해 다시 올라가는 과정을 'bubble phase'라고 한다.

하지만 이 순서대로 이벤트가 수행될 경우 target 이벤트 외에 다른 이벤트들도 중복 수행되는 문제점이 있다.

이를 해결하기 위해서 브라우저에서는 currentTarget과 target이 일치하지 않는 경우, 캡처 단계에서 실행될 것인지 버블 단계에서 실행될 것인지 선택할 수 있도록 제한한다. 브라우저의 기본 값은 버블이며, addEventListener의 3번째 인자(useCapture)로 설정할 수 있다. 이를 설정해줌으로써 이벤트가 중복되지 않고 실행될 수 있게 된다.

 

이벤트 버블링 및 캡쳐링이란?

이벤트 버블링(event bubbling)은 HTML에서 이벤트가 발생했을 때, 해당 요소에서 이벤트가 처리된 후, 상위 요소로 이벤트가 전파되는 방식이다. 반대로 이벤트 캡쳐링(Event Captureing)은 바깥 노드로부터 시작해서 안쪽으로 퍼지는 방식이다.

버블링 및 캡쳐링을 방지하기 위해서는 이벤트 객체의 e.stopPropagation() 메서드를 사용하여 이벤트 전파를 중지시키거나, 이벤트 핸들러에서 이벤트가 발생한 요소를 확인하여 처리해야 한다.

 

이벤트 위임이란?

이벤트 위임은 개별 요소에 이벤트 핸들러를 생성하는 대신 상위 요소에만 이벤트 핸들러를 생성하고 해당 이벤트 핸들러에서 어떤 요소에서 이벤트가 발생했는지 조건문을 설정하는 것이다. 즉, 이벤트를 처리하는 핸들러 함수를 부모 요소에 등록해놓으면, 자식 요소에서 발생한 이벤트도 모두 처리할 수 있다. 이를 활용하면, 여러 개의 하위 요소에서 발생하는 이벤트를 하나의 이벤트 핸들러로 바인딩하는 이벤트 위임 처리를 할 수 있다.

<div id="div-content">
  <span id="span-content">
    <button id="btn">버튼</button>
  </span>
</div>

위 예제에서 상위 요소는 div이므로 div에만 이벤트 핸들러를 등록한다. 그리고 어디서 이벤트가 발생했는지 파악하기 위해 이벤트 객체(e)를 사용하며, 어떤 요소(e.target)에서 이벤트가 발생했는지 조건문을 통해 확인한다.

// 상위 요소인 id가 "div-content"인 div 노드만 접근함
const divNode = document.getElementById("div-content");

// div 노드에만 이벤트 리스너를 설정
divNode.addEventListener("click", function (e) {
  const id = e.target.id;
  
  // 이벤트 객체의 target.id로 조건문을 설정
  if (id === "div-content") {
    console.log("div-content id Click");
  } else if (id === "span-content") {
    console.log("span-content id Click");
  } else if (id === "btn") {
    console.log("btn id Click");
  }
});

이벤트 위임은 table 혹은 ul 등의 부모 엘리멘트 안에서 각각의 항목에 대해 동일한 종류의 처리를 해줘야할 때 사용할 수 있다.

 

마치며, 

이해에 참고한 유튜브 영상이 있다. 이미지가 이해에 큰 도움을 주어 이미지도 캡쳐하여 작성해보았다. 강추!

https://www.youtube.com/watch?v=7gKtNC3b_S8 

이벤트 위임 이해에 도움이 된 블로그)

https://developer-talk.tistory.com/886

 

[JS]이벤트 위임(Event Delegation)이란?

이벤트 위임(Event Delegation) JavaScript의 대부분 이벤트는 이벤트 흐름(Event Flow)의 이벤트 캡처링, 이벤트 버블링 단계를 거칩니다. 일반적으로 addEventListener() 메서드의 세 번째 매개변수로 true를 전

developer-talk.tistory.com

 

반응형