본문 바로가기

언어(JS,TS)/그룹스터디

그룹스터디 [DOM: 이벤트 위임(Event Delegation)이란?]

     

    이벤트 위임(Event Delegation)

    이벤트 위임은 실제 바닐라 JS로 웹 앱을 구현할 때 자주 사용하게 되는 코딩 패턴입니다.

    이벤트 위임을 한 문장으로 요약해보면

    ‘하위 요소에 각각 이벤트를 붙이지 않고 상위 요소에서 하위 요소의 이벤트들을 제어하는 방식’입니다.

    코드

    <!-- index.html -->
    <body>
      <h1>오늘의 할 일</h1>
      <ul class="itemList">
        <li>
          <input type="checkbox" id="item1" />
          <label for="item1">학습1</label>
        </li>
        <li>
          <input type="checkbox" id="item2" />
          <label for="item2">학습2</label>
        </li>
      </ul>
      <script src="./index.js"></script>
    </body>
    var inputs = document.querySelectorAll('input');
    inputs.forEach(function(input) {
    	input.addEventListener('click', function(event) {
    		alert('clicked');
    	});
    });
     

    위 코드는 할 일 목록을 간단한 리스트 아이템으로 나타낸 코드입니다.

    할 일 목록의 체크 박스를 클릭했을 때 클릭 이벤트 리스너가 동작하는 모습

     

     

    자바스크립트 querySelectorAll()를 이용해 화면에 존재하는 모든 인풋 박스 요소를 가져온 다음

    각 인풋 박스의 요소에 클릭 이벤트 리스너를 추가합니다.

    화면을 실행시키고 각 리스트 아이템의 인풋 박스(체크 박스)를 클릭하면 위와 같이 경고 창이 표시됩니다.

     

    그런데 만약 여기서 할 일이 더 생겨서 리스트 아이템을 추가하면 문제가 생깁니다

    // 기존코드
    let inputs = document.querySelectorAll('input');
    inputs.forEach(function (input) {
      input.addEventListener('click', function (event) {
        alert('clicked');
      });
    });
    
    // 새 리스트 아이템을 추가하는 코드
    let itemList = document.querySelector('.itemList');
    
    let li = document.createElement('li');
    let input = document.createElement('input');
    let label = document.createElement('label');
    let labelText = document.createTextNode('추가로 생성된 일정');
    
    input.setAttribute('type', 'checkbox');
    input.setAttribute('id', 'item3');
    label.setAttribute('for', 'item3');
    label.appendChild(labelText);
    li.appendChild(input);
    li.appendChild(label);
    itemList.appendChild(li);

    새로 추가된 리스트 아이템(이벤트 위임 학습)에서 클릭 이벤트가 동작하지 않는 모습이 보입니다

     

     

    코드를 다시 살펴보면, 인풋 박스에 클릭 이벤트 리스너를 추가하는 시점에서 리스트 아이템은 두 개입니다.

    그래서 새롭게 추가된 리스트 아이템에는 클릭 이벤트 리스너가 등록되지 않았습니다.

    그러면 메모지 같이 매번 생성되는 프로젝트에서는 매번 이벤트를 추가해야하는 번거러움이 생기게 됩니다

    그래서 이러한 문제를 해결할 수 있는 방법이 바로 이벤트 위임(Event Delegation)입니다.

     

     

    앞에서 살펴본 코드를 아래와 같이 변경해보겠습니다.

    // // 기존코드
    // let inputs = document.querySelectorAll('input');
    // inputs.forEach(function (input) {
    //   input.addEventListener('click', function (event) {
    //     alert('clicked');
    //   });
    // });
    
    // 변경된이벤트
    let itemListObj = document.querySelector('.itemList');
    itemListObj.addEventListener('click', function (event) {
      console.log('event.target:', event.target);
      alert(`${event.target.id}`);
    });
    
    // 새 리스트 아이템을 추가하는 코드
    let itemList = document.querySelector('.itemList');
    
    let li = document.createElement('li');
    let input = document.createElement('input');
    let label = document.createElement('label');
    let labelText = document.createTextNode('추가로 생성된 일정');
    
    input.setAttribute('type', 'checkbox');
    input.setAttribute('id', 'item3');
    label.setAttribute('for', 'item3');
    label.appendChild(labelText);
    li.appendChild(input);
    li.appendChild(label);
    itemList.appendChild(li);
     

    화면의 모든 인풋 박스에 일일이 이벤트 리스너를 추가하는 대신 이제는 인풋 박스의 상위 요소인

    ul 태그, .itemList에 이벤트 리스너를 달아놓고 하위에서 발생한 클릭 이벤트를 감지합니다.(이벤트 버블링

     

    결과

    새로 추가된 리스트 아이템에서 클릭 이벤트가 정상적으로 동작하는 모습

    클릭한 오브젝트도 잘 확인이 됩니다