[JS] 이벤트 위임

Hailey·2022년 7월 15일
0
post-thumbnail

강의 링크: https://youtu.be/-fFNuNsR8q4
자료 링크: https://ko.javascript.info/event-delegation
파트: JS

이벤트 위임

  1. 컨테이너에 하나의 핸들러를 할당합니다.
  2. 핸들러의 event.target을 사용해 이벤트가 발생한 요소가 어디인지 알아냅니다.
  3. 원하는 요소에서 이벤트가 발생했다고 확인되면 이벤트를 핸들링합니다.
  • 이벤트 위임의 장점
    • 많은 핸들러를 할당하지 않아도 되기 때문에 초기화가 단순해지고 메모리가 절약됩니다.
    • 요소를 추가하거나 제거할 때 해당 요소에 할당된 핸들러를 추가하거나 제거할 필요가 없기 때문에 코드가 짧아집니다.
    • innerHTML이나 유사한 기능을 하는 스크립트로 요소 덩어리를 더하거나 뺄 수 있기 때문에 DOM 수정이 쉬워집니다.
  • 이벤트 위임의 단점
    • 이벤트 위임을 사용하려면 이벤트가 반드시 버블링 되어야 합니다. 하지만 몇몇 이벤트는 버블링 되지 않습니다. 그리고 낮은 레벨에 할당한 핸들러엔 event.stopPropagation()를 쓸 수 없습니다.
    • 컨테이너 수준에 할당된 핸들러가 응답할 필요가 있는 이벤트이든 아니든 상관없이 모든 하위 컨테이너에서 발생하는 이벤트에 응답해야 하므로 CPU 작업 부하가 늘어날 수 있습니다. 그런데 이런 부하는 무시할만한 수준이므로 실제로는 잘 고려하지 않습니다.

코드로 보는 이벤트 위임

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Event Delegation</title>
    <link rel="stylesheet" href="../reset.css" />
    <style>
      body {
        display: flex;
        align-items: center;
        justify-content: center;
      }
      @keyframes pointer-ani {
        0% {
          transform: scale(0);
        }
        50% {
          transform: scale(1);
        }
        100% {
          transform: scale(1.5);
          opacity: 0;
        }
      }
      .pointer {
        position: absolute;
        left: 0;
        top: 0;
        width: 60px;
        height: 60px;
        margin: -30px 0 0 -30px;
        border-radius: 50%;
        background: url('../images/ilbuni2.png') no-repeat 0 0 / cover;
        transform: scale(0);
        animation: pointer-ani 0.5s linear;
      }
      .menu {
        display: flex;
        margin-top: 10vh;
        padding: 2em;
        border-radius: 20px;
        background: #eee;
      }
      .menu-btn {
        display: inline-flex;
        align-items: center;
        margin: 0 1em;
        padding: 0.5em 1em 0.5em 0.5em;
        border: 5px solid white;
        border-radius: 20px;
        outline: 0;
        font: 900 1.2rem NotoSans;
        background: linear-gradient(
          0deg,
          rgba(223, 210, 0, 1) 0%,
          rgba(255, 240, 0, 1) 24%,
          rgba(255, 240, 0, 1) 70%,
          rgba(255, 255, 255, 1) 100%
        );
        box-shadow: rgba(0, 0, 0, 0.1) 0 0 0 1px inset;
      }
      .btn-label {
        text-shadow: rgba(255, 255, 255, 1) 0 1px 0;
        /*pointer-events: none;*/
        /* 클릭 이벤트를 받지 않기 위한 CSS 방법 */
      }
      .icon {
        width: 60px;
        /*pointer-events: none;*/
      }
    </style>
    <script src="IlbuniPointer.js"></script>
    <script>
      window.addEventListener('DOMContentLoaded', () => new IlbuniPointer());
    </script>
  </head>
  <body>
    <div class="menu">
      <button class="menu-btn" data-value="1">
        <img class="icon" src="../images/ilbuni1.png" alt="" />
        <span class="btn-label">일분이 1</span>
      </button>
      <button class="menu-btn" data-value="2">
        <img class="icon" src="../images/ilbuni2.png" alt="" />
        <span class="btn-label">일분이 2</span>
      </button>
      <button class="menu-btn" data-value="3">
        <img class="icon" src="../images/ilbuni3.png" alt="" />
        <span class="btn-label">일분이 3</span>
      </button>
    </div>

    <script>
      const menu = document.querySelector('.menu');

      function clickHandler(event) {
        // console.log(event);
        // console.log(event.target);
        // console.log(event.currentTarget);
        // console.log(event.target.getAttribute('data-value'));
        // 이벤트 객체 중 currentTarget 과 target 비교 해보기(span, img 등 나오기 때문에 디테일하게 추가)
        // 1.js로 하는 방법 => 자식 요소 선택 시, button 부모 요소 찾을 수 있게 코드 입력
        // 2.css로 하는 방법 => event 처리를 하지 않을 속성에 pointer-events: none;
        // 단점 : 하위의 영역을 인지하지 못하기 때문에 사용할 수 없음 =>  처음에 설계를 잘해야함

        // console.log(event.target.dataset.value);
        //data-value의 객제가 dataset에 자동으로 생성

        let elem = event.target;

        //menu-btn을 부모요소 찾기 위한 반복문
        while (!elem.classList.contains('menu-btn')) {
          elem = elem.parentNode;

          // 버튼의 바깥 영역을 제한해줘야 함 BODY영역으로 나갈 시 종료
          if (elem.nodeName == 'BODY') {
            elem = null;
            return;
          }
        }

        console.log(elem.dataset.value);
      }

      menu.addEventListener('click', clickHandler);
    </script>
  </body>
</html>
profile
팀에서 꼭 필요한 프론트엔드 개발자가 되고 싶습니다.

0개의 댓글