JAVASCRIPT -

이벤트 위임(Event Delegation)

  • -

이벤트 위임 (Event Delegation)

안녕하세요 TriplexLab입니다 :)
오늘은 이벤트 위임에 관해서 살펴보도록 하겠습니다.

✍️ 이벤트 위임 코드

다음 코드는 이벤트를 핸들러를 등록하고, 클래스를 토글 하는 코드입니다.
근데 아래 코드는 한 가지 문제가 있습니다. 

<div id="list"></div>

 

//이벤트 위임 (Event Delegation)
(function() {
    const list = document.querySelector('#list');
            
    for (let item of list.children) {
        item.addEventListener('click', function(e) {
            e.target.classList.toggle('done');
        });
    }
})();

 

다음과 같이 엘리먼트를 새로 추가하게 되면 이벤트 핸들러가 동작하지 않아요. 

const li = document.createElement('li');
li.classList.add('item');
li.textContent = '일기 쓰기';
list.append(li);

그래서 엘리먼트를 추가 할때마다 이벤트 핸들러도 새 추가해야 하는 문제가 있습니다.

이럴 때 이벤트 버블링을 활용하면 간단하게 해결할 수가 있습니다. 

버블링 계념에 따르면 부모요소가 자식 요소에서 발생하는 이벤트를 감지할 수 있고, 
이벤트 객체의 target프로퍼티가 항상 이벤트 발생 위치를 담고 있기 때문에 
다음과 같이 부모요소에 이벤트 핸들러를 하나만 등록해줘도 모든 자식 요소의 이벤트를 다룰 수 있게 됩니다.

list.addEventListener('click', function(e) {
    e.target.classList.toggle('done');
});

하지만 여기서 한가지 문제가 있습니다.
바로 부모 요소에 위임을 한 것이기 때문에 
자식 요소를 제외한 부모 요소를 클릭해도 동작한다는 것입니다. 이것을 해결하기 위해서는
다음과 같이 조건문을 활용해서 target프로퍼티에 해당 클래스가 있는지 없는지 bloon형태로 판단하면 해결됩니다.

list.addEventListener('click', function(e) {
    if(e.target.classList.contains('item')) {
        e.target.classList.toggle('done');
    }
});

이렇게 이벤트 버블링을 활용하면 
1️⃣ 정말 유연하게 코드를 작성할 수 있다는 장점 
2️⃣ 여러게의 이벤트 핸들러를 만들지 않아도 된다는 장점 (코드를 적게 작성해도 된다.)

실제로 이코드가 동작할 때 프로그램의 성능에도 긍정적인 영향을 미치니깐 이벤트를 다루고자 할 때 
이벤트 위임을 우선적으로 작성한 다음에, 불가피할 때 개별적으로 이벤트 핸드러를 등록하는 방식을 사용하는 것이 
좋을 것 같습니다.


✍️ 전체 코드 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .done {
            text-decoration:dotted;
        }
    </style>
</head>
<body>
    <div id="main">
        <h2 id="title">오늘 할 일</h2>
        <ul id="list">
          <li class="item">자바스크립트 공부하기</li>
          <li class="item">고양이 화장실 청소하기</li>
          <li class="item">고양이 장난감 쇼핑하기</li>
        </ul>
    </div>

    <script>
    (function() {
        const list = document.querySelector('#list');
        
        list.addEventListener('click', function(e) {
            if(e.target.classList.contains('item')) {
                e.target.classList.toggle('done');
            }
        });

       const li = document.createElement('li');
       li.classList.add('item');
       li.textContent = '일기 쓰기';
       list.append(li);
       
       li.addEventListener('click', function(e) { // 당연하게도 자삭요소에서 이벤트 버블링을 막는 메소드를 주면 이벤트는 동작하지 않습니다.
         e.stopPropagation(); // 이벤트 버블링을 막는것은 피하는것이 좋습니다.
       });
       
    })();
    </script>
</body>
</html>

 

👇 이벤트 버블링 설명

e.stopPropagation(); 꼭 필요한 상황이 아니면, 이벤트 버블링을 막는 것은 피하는 것이 좋습니다.
그 이유는 지금처럼. item에서 이벤트 버블링을 막아버리면, 바로 위에 있는 #list뿐만 아니라, 모든 부모 요소 입장에서
.item들 영역만큼의 이벤트를 발생시킬 범위가 사라져 보리는 것입니다.

예를 들어서 페이지 전체를 걸쳐서 어떤 이벤트를 만들고 싶은 경우에는 결국 document, body 같은 문서 전체를 다룰 수 있는 상위 요소의 이벤트 핸들러를 만들어 줄텐데, 버블링이 막혀있는 구간이 존재하면 당연히 이벤트(click)가 발생했을 때 버블링이 막혀버리기 때문에 그 부부만 우리가 원하는 이벤트 결과를 얻지 못합니다.  

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.