본문 바로가기
프론트엔드/JS 공부

이벤트 위임(event delegation)에 대한 정리

by 학습하는 청년 2024. 4. 6.

최종 수정 : 2024-04-06

연결 지식

이벤트 전파(event propagation)
https://young-taek.tistory.com/213


1. 이벤트 위임(event delegation)

캡처링과 버블링을 활용하면 강력한 이벤트 핸들링 패턴인 이벤트 위임(event delegation)을 구현할 수 있다. 비슷한 방식으로 여러 요소를 다뤄야 할 때 사용한다. 이벤트 위임을 사용하면 핸들러를 할당하지 않고, 요소의 공통 조상에 이벤트 핸들러를 단 하나만 할당해도 여러 요소를 한꺼번에 다룰 수 있다.

 

장점

1. 많은 핸들러를 할당하지 않아도 되기 때문에 초기화가 단순해지고 메모리가 절약된다.

2. 요소를 추가하거나 제거할 때 해당 요소에 할당된 핸들러를 추가하거나 제거할 필요가 없어져 코드가 짧아진다.

3. innerHTML 이나 유사한 기능을 하는 스크립트로 요소 덩어리를 더하거나 뺄 수 있어서 DOM 수정이 쉬워진다.

 

단점

이벤트 위임을 사용하려면 이벤트가 반드시 버블링 되어야 한다. 

  <div class="menu">
    <button class="menu-btn" data-value="1">
      <span class="btn-label">버튼 1</span>
    </button>
    <button class="menu-btn" data-value="2">
      <span class="btn-label">버튼 2</span>
    </button>
    <button class="menu-btn" data-value="3">
      <span class="btn-label">버튼 3</span>
    </button>
  </div>

위 코드의 버튼 캡쳐 이미지

버튼에 각각 이벤트 핸들러를 작성하여 처리하는 방법은 메모리 낭비나 다름없다. 이보다는 버튼들의 부모 요소에 이벤트 리스너를 연결하여 자식 요소로 있는 버튼들이 동작하도록 연결(바인딩)하는 방식으로 처리할 수 있다.

 

[방법 1]

버튼 안 요소(span)이 이벤트 영향을 받지 않게 만들어서, 버튼만 동작하도록 하기
/* 방법 1) 
이벤트 영향을 받지 않게끔 설정해주는 CSS 
- 하위에 있는 요소를 타깃으로 잡을 수 없다는 것을 유념해야 한다.*/
    
.btn-label {
  pointer-events: none;
}

 

[방법 2-1]

스크립트 활용
const $menu = document.querySelector('.menu');

function clickHandler(e) {
  let elem = e.target;
  // div 태그(menu)의 자식 요소가 얼마나 있을지 모르기 때문에 while문으로 작성
  while (!elem.classList.contains('menu-btn')) {
    elem = elem.parentNode;
    
    // 버튼 영역 바깥을 클릭했을 때, 종료
    if (elem.nodeName == "BODY") {
      elem = 'null';
      return;
    }
  }
}

$menu.addEventListener('click', clickHandler);

 

[방법 2-2]

스크립트를 동적으로 활용
이는 부모요소에 이벤트 위임을 했기 때문에 가능한 것이다. div(menu)의 자식 요소로 생성한다.

 

<body>
  <div class="menu">
    <!-- 여기에 버튼에 대한 코드가 생기는 것과 같다. -->
  </div>
  <script>
    const $menu = document.querySelector('menu');
    
    function clickHandler(e) {
      let elem = e.target;
      while (!elem.classList.contains('menu-btn')) {
        elem = elem.parentNode;
        if (elem.nodeName == "BODY") {
          elem = 'null';
          return;
        }
      }
    }
    $menu.addEventListener('click', clickHandler);
    window.addEventListener('click', () => {
      const htmlStr = `
        <button class="menu-btn" data-value="1">
          <span class="btn-label">버튼 1</span>
        </button>
        <button class="menu-btn" data-value="2">
          <span class="btn-label">버튼 2</span>
        </button>
        <button class="menu-btn" data-value="3">
          <span class="btn-label">버튼 3</span>
        </button>
      `;
      $menu.innerHTML = htmlStr;
    });
  </script>
</body>

 

+) 추가 공부 필요

matches 메서드 활용


참고 자료

https://ko.javascript.info/event-delegation

 

이벤트 위임을 처리하는 방법

https://youtu.be/-fFNuNsR8q4?si=l8UPZ4g9jzlYvNZV

댓글