ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 이벤트 위임 - 캡처링/버블링 (Event Delegation - Captruring / Bubbling)
    frontend/javascript&web 2022. 2. 21. 19:45

    쉽게 이해하는 이벤트 위임(Event Delegation)

     

    이벤트

    • 특정 행위시 발생하는 사건

     

    브라우저는 이벤트를 감지할 수 있고 이벤트 발생 시 알려줄수 있으며 이를 통해 웹 페이지와 상호작용가능하며 핸들러를 통해 원하는 함수와 연결해 사용할 수 있습니다.

     

    이벤트 타입

    마우스 click(클릭), dbclick(더블 클릭), mouserover(마우스 오버), mouseout(마우스 아웃), mousedown(마우스 눌림),  mouseup(마우스 뗌), mousemove(마우스 움직임), contextmenu(오른쪽 마우스)
    키보드 keydown(키 눌림), keyup(키 뗌), keypress(키 눌린상태)
    focus(포커스 인), blur(포커스 아웃), change(값 변경), submit(제출), reset(리셋), select(드래그 선택시)

     

    이벤트 등록

    let button = document.querySelector("button");
    button.addEventListener("click",event);

    이벤트 해제

    let button = document.querySelector("button");
    button.removeEventListener("click",event);

    위에서 이벤트가 무엇인지 그리고 어떤것들이 있는지 이벤트 등록과 해제는 어떻게 하는 것인지 간략하게 알아보았습니다. 본격적으로 이벤트 위임을 이해하기 위한 이벤트 버블링과 캡처링에 대해서 예제와 함께 알아보겠습니다.

     

    이벤트 버블링과 캡처링

     

    자바스크립트는 이벤트가 발생하게 되면 이벤트가 발생한 노드를 찾기위해 DOM트리를 탐색하게 됩니다. 탐색의 과정은 이벤트 버블링과 이벤트 캡처링이 있습니다.

     

    사용법

    // Default Bubbling
    button.addEventListener('click',event);
    // Capturing
    button.addEventListener('click',event,{captrue:true});

     

    이벤트 버블링

     

    이벤트 버블링은 특정 Element에서 이벤트가 발생했을때 해당 이벤트가 상위의 노드 들로 전달되어 가는 특성을 말합니다.

     

     

    이벤트 캡처링

     

    이벤트 캡처링은 이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식입니다. document 루트 혹은 가장 바깥쪽 노드에서 이벤트가 발생한 타겟 노드까지 내려가는 탐색방식입니다.

     

     

    예시

    <!DOCTYPE html>
    
    <html lang="ko">
      <head>
        <meta charset="UTF-8"/>
        <title>FRONTEND RYUHOJIN</title>
      </head>
      <body>
      <header>
        <nav>
          <ul>
            <li>메뉴 1</li>
            <li>메뉴 2</li>
          </ul>
        </nav>
      </header>
      <script>
      function eventPropagation(isCapturing) {
        document.querySelector("body").addEventListener("click",function() {
          console.log("body")},{capture : isCapturing});
        document.querySelector("header").addEventListener("click",function() {
          console.log("header")},{capture : isCapturing});
        document.querySelector("nav").addEventListener("click",function() {
          console.log("nav")},{capture : isCapturing});
        document.querySelector("ul").addEventListener("click",function() {
          console.log("ul")},{capture : isCapturing});
        let li = document.querySelectorAll("li");
        for(let i = 0 , len = li.length ; i < len ; i++ ) {
          li[i].addEventListener("click",function() {
            console.log("target")},{capture : isCapturing});
          }
        }
      eventPropagation(false); // 이벤트 버블링
      // eventPropagation(true); // 이벤트 캡처링
      </script>
      </body>
    </html>

    해당 코드를 복사 붙여넣기 하여 HTML문서로 만들어 테스트해보시면 이해가 더 쉬울 것이라고 생각됩니다. 버블링을 하였을때는 아래와 같은 모습을 볼 수 있을 것입니다.

    li를 클릭하였을때 콘솔에는 위와 같이 찍히게 됩니다. 이벤트 버블링 시에는 해당 타겟 부터 상위노드로 이벤트가 전파 되는 것을 볼 수 있습니다. 반대로 캡처링으로 돌리게 되면 아래와 같은 결과를 얻을 수 있으실 겁니다.

    상위 노드에서 해당 엘리먼트 까지 내려가면서 탐색하는걸 볼 수 있습니다.

     

    이벤트 전파 방지

     

    이러한  불필요한 이벤트 전파때문에 상위 요소에 같은 이벤트를 처리하는 다른 리스너가 등록되있는 경우 원하지 않는 동작을 일으킬 수 있습니다. 이런 점을 방지 하기 위해서는 아래와 같은 작업을 하면 됩니다.

    function api(event) {
      event.stopPropagation();
    }

    코드에서도 보시다 싶히 이벤트 전파를 막는 코드입니다. 이렇게 하시면 해당 이벤트에서 더이상 이벤트 전파가 일어나지 않을 것입니다.

     

    이벤트 위임

    • 상위요소에서 하위요소의 이벤트를 관리하는 방식

     

    우리가 앞에서 이벤트 버블링과 캡처링을 배운 것은 사실 이벤트 위임을 위해 배웠다고 할 수 있습니다. 이벤트 위임이 필요한 이유는 다음과 같습니다.

    • 동적 엘리먼트 이벤트 처리 용이
    • 상위 엘리먼트에서만 이벤트 리스너를 관리해서 하위 엘리먼트 추가 / 삭제 쉬움
    • 이벤트 핸들러 관리 용이
    • 메모리 사용 최적화 가능

     

    예시

    <!DOCTYPE html>
    
    <html lang="ko">
      <head>
        <meta charset="UTF-8"/>
        <title>FRONTEND RYUHOJIN</title>
      </head>
      <body>
      <header>
        <nav>
          <ul class="menu-list">
            <li class="menu1">메뉴 1</li>
            <li class="menu2">메뉴 2</li>
          </ul>
        </nav>
      </header>
      <script>
      let li = document.querySelectorAll("li");
      for(let i = 0, len = li.length; i < len; i++){
      	li[i].addEventListener("click",(event)=>{
          console.log(event.target.className);
        })
      }
      let menuList = document.querySelector(".menu-list");
      let createLi = document.createElement("li");
      createLi.setAttribute("id","menu3");
      let label = document.createTextNode("메뉴 3");
      createLi.appendChild(label);
      menuList.appendChild(createLi);
      </script>
      </body>
    </html>

    위의 코드는 두개의 메뉴가 있는 상태에서 한개의 메뉴가 동적으로 생성되는 케이스 입니다. 위와 같은 케이스에서는 실제로 메뉴3을 클릭했을때 발생하는 이벤트를 등록하기 위해선 이벤트 위임을 사용하지 않는다면 일일이 addEventListener를 달아줘야됩니다. 하지만 이런 방식으로 작업하게 되면 메뉴가 지속적으로 늘어나게 된다면 코드의 길이가 계속 늘어나고 관리포인트 또한 증가할 것입니다.

    <!DOCTYPE html>
    
    <html lang="ko">
      <head>
        <meta charset="UTF-8"/>
        <title>FRONTEND RYUHOJIN</title>
      </head>
      <body>
      <header>
        <nav>
          <ul class="menu-list">
            <li class="menu1">메뉴 1</li>
            <li class="menu2">메뉴 2</li>
          </ul>
        </nav>
      </header>
      <script>
      let menuList = document.querySelector(".menu-list");
      menuList.addEventListener("click",(event)=>{ console.log(event.target.className);});
      let createLi = document.createElement("li");
      createLi.setAttribute("class","menu3");
      let label = document.createTextNode("메뉴 3");
      createLi.appendChild(label);
      menuList.appendChild(createLi);
      </script>
      </body>
    </html>

    그래서 우리는 위의 코드와 같이 상위 노드("menu-list")에서 이벤트 리스너를 달아놓고 하위에서 발생한 이벤트를 감지하여 사용(이벤트 버블링)하면 됩니다. 

     

    이벤트 위임과 그 사전 지식인 이벤트 버블링, 캡처링 그리고 이벤트엔 어떤 것들이 있고 이것을 등록 및 해제 하는것에 대해서 전반적으로 알아보았습니다. 이벤트 버블링과 캡처링과 같은 위임에 관한 내용은 프론트엔드 단골 면접 질문 중 하나이니 알고 있으면 좋을 것 같습니다.

    반응형

    댓글

Designed by Tistory.