JavaScript/DOM

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

DevStory 2022. 12. 11.

이벤트 위임(Event Delegation)

JavaScript의 대부분 이벤트는 이벤트 흐름(Event Flow)의 이벤트 캡처링, 이벤트 버블링 단계를 거칩니다. 일반적으로 addEventListener() 메서드의 세 번째 매개변수로 true를 전달하지 않은 이상 이벤트 캡처링 단계는 수행되지 않고 이벤트 버블링 단계를 거치는데, 이벤트 버블링은 타겟에서 이벤트가 발생하면 타겟에서 위로 이벤트를 전파하는 것을 말합니다.

 

아래 예제에서 <button> 태그에서 click 이벤트가 발생하면, button → span → div로 이벤트가 전파됩니다.

<div id="div-content">
  <span id="span-content">
    <button id="btn">버튼</button>
  </span>
</div>
const divNode = document.getElementById("div-content");
const spanNode = document.getElementById("span-content");
const btnNode = document.getElementById("btn");

divNode.addEventListener("click", function () {
  console.log("divNode Click");
});

spanNode.addEventListener("click", function () {
  console.log("spanNode Click");
});

btnNode.addEventListener("click", function () {
  console.log("btnNode Click");
});

[실행 결과]

이벤트 버블링에 의해 <button> 태그에서 click 이벤트가 발생하면, 해당 이벤트는 최상위 객체인 Document까지 전파됩니다. 위 코드의 문제점은 상위 요소의 이벤트도 실행함으로써 개발자가 원하지 않는 결과를 발생시킬 수 있습니다.

 

이번 포스팅은 여러 이벤트 리스너를 등록하지 않고 상위 요소에만 이벤트 리스너를 등록하는 이벤트 전파 구현 방법을 소개합니다.


이벤트 위임 구현

이벤트 위임은 개별 요소에 이벤트 리스너(혹은 이벤트 핸들러)를 생성하는 대신 상위 요소에만 이벤트 리스너를 생성하고 해당 이벤트 리스너에서 어떤 요소에서 이벤트가 발생했는지 조건문을 설정하는 것입니다.

 

위 예제에서 상위 요소는 div이므로 div에만 이벤트 핸들러를 등록합니다. 그리고 어디서 이벤트가 발생했는지 알아야 하므로 이벤트 객체(e)를 사용하며, 어떤 요소(e.target)에서 이벤트가 발생했는지 조건문을 설정합니다.

<div id="div-content">
  <span id="span-content">
    <button id="btn">버튼</button>
  </span>
</div>
// 상위 요소인 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");
  }
});

조건문은 위 예제처럼 id 프로퍼티로 설정하거나 아래 예제처럼 태그 이름으로 설정할 수도 있습니다.

const divNode = document.getElementById("div-content");

divNode.addEventListener("click", function (e) {
  const tagName = e.target.tagName;

  if (tagName === "DIV") {
    console.log("div Click");
  } else if (tagName === "SPAN") {
    console.log("span id Click");
  } else if (tagName === "BUTTON") {
    console.log("button Click");
  }
});
반응형

이벤트 위임의 이점

여러 개의 이벤트 리스너를 등록하지 않고 상위 요소에 하나의 이벤트 리스너만 등록하는 것을 이벤트 위임이라고 합니다. 이벤트 위임을 사용하면 다음과 같은 이점을 얻을 수 있습니다.

 

메모리 사용량 감소

JavaScript에서 함수는 객체입니다. 함수가 많을수록 메모리 사용량이 증가하고 함수가 적을수록 메모리 사용량이 감소합니다.

 

[이벤트 위임 사용 전]

// 개별 요소를 접근해야함
const divNode = document.getElementById("div-content");
const spanNode = document.getElementById("span-content");
const btnNode = document.getElementById("btn");

// 개별 요소마다 이벤트 리스너를 등록해야함
divNode.addEventListener("click", function () {
  console.log("divNode Click");
});

spanNode.addEventListener("click", function () {
  console.log("spanNode Click");
});

btnNode.addEventListener("click", function () {
  console.log("btnNode Click");
});

[이벤트 위임 적용 후]

// 상위 요소인 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");
  }
});

이벤트 위임을 적용하면 최상위 요소만 접근하면 되므로 spanNode, btnNode라는 변수는 필요 없습니다. 그리고 addEventListener() 메서드를 한 번만 호출하면 되므로 이벤트 핸들러 함수도 하나만 존재하면 됩니다.

 

개발자가 의도한 대로 동작

여러 개의 이벤트 리스너를 등록하면 이벤트 버블링에 의해 상위 요소의 이벤트 리스너도 실행됩니다. 상위 요소의 이벤트 리스너에 문제가 되는 코드가 존재한다면 이벤트가 동작할 때, 의도하지 않은 결과를 초래할 수 있습니다.

 

이벤트 위임을 적용하면 조건문에 의해 원하는 요소에 원하는 동작을 수행하도록 코드를 구현할 수 있습니다.


정리

  • 이벤트 위임은 이벤트 버블링을 활용하여 상위 요소에만 이벤트 리스너를 등록하는 기법입니다.
  • 이벤트 위임을 적용하면 메모리 사용량이 감소하며 코드를 더 간결하게 구현할 수 있습니다.
반응형

댓글