event delegation

DOM요소마다 요소마다 핸들러를 할당하지 않고, 요소의 공통 조상에 이벤트 핸들러를 단 하나만 할당해도 여러 요소를 한꺼번에 다룰 수 있는 기법.

Example

Clicked:

Implementation

버튼 3개가 부모 div 안에 있고, 부모 div 에만 onClick 이벤트가 바인딩 되어있다. 부모는 클릭 이벤트가 발생했을때 어떤 자식이 클릭되었는지 감지하고 해당 버튼 DOM 객체를 찾아야한다.

이것을 구현하기 위해 주의해야할 사항은 다음과 같다.

  • 버튼이 아닌 부모 div 가 클릭되면 이벤트는 무시한다.
  • button 요소 안의 아이콘과 택스트가 클릭되면 해당 요소의 부모요소인 button 을 찾아야한다.

vue

<template>
  <div @click="onClick">
    <button data-value="menu1">
      <i class="icon"></i>
      <p>Menu1</p>
    </button>
    <button data-value="menu2">
      <i class="icon"></i>
      <p>Menu2</p>
    </button>
    <button data-value="menu3">
      <i class="icon"></i>
      <p>Menu3</p>
    </button>
  </div>
</template>

방법1. CSS

pointer-event: none 을 사용, 버튼 안의 아이콘과 택스트를 클릭해도 그 요소의 부모 button 이 이벤트의 target 이 되도록 만든다.

vue

<script setup>
const onClick = (e) => {
  // e.currentTarget 은 이벤트가 지정된 부모 태그
  // e.target 은 이벤트가 트리거 된 태그 (자식 부모 둘다 가능)

  if (e.currentTarget === e.target) {
    // 부모에서 트리거 된 이벤트는 무시한다.
    return;
  }

  const clickedBtn = e.target;
    
  // do something
  console.log(clickedBtn)
};
</script>

<template>
  <div @click="onClick">
    <button data-value="menu1">
      <i class="pointer-events-none"></i>
      <p class="pointer-events-none">Menu1</p>
    </button>
    <button data-value="menu2">
      <i class="pointer-events-none"></i>
      <p class="pointer-events-none">Menu2</p>
    </button>
    <button data-value="menu3">
      <i class="pointer-events-none"></i>
      <p class="pointer-events-none">Menu3</p>
    </button>
  </div>
</template>

방법2. JS closest 사용

vue

<script setup>
const onClick = (e) => {
  // e.currentTarget 은 이벤트가 지정된 부모 태그
  // e.target 은 이벤트가 트리거 된 태그 (자식 부모 둘다 가능)

  if (e.currentTarget === e.target) {
    // 부모에서 트리거 된 이벤트는 무시한다.
    return;
  }

  const closestBtn = e.target.closest('button');
  
  if (closestBtn) {
    const clickedBtn = closestBtn;

    // do something
    console.log(clickedBtn)
  }
};
</script>