[JS] 이벤트 delegation이란?

kysung95·2021년 5월 18일
1

짤막글

목록 보기
10/15
post-thumbnail

안녕하세요. 김용성입니다.
혹시 JavaScript의 event delegation이라는 것을 들어보셨나요?
오늘은 이것에 대한 포스팅을 할까 합니다.

event delegation의 필요성

쉬운 설명을 위해
html,css,js를 통해 간단한 TodoList를 만들어 보도록 할께요.

html

<!-- TodoList.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">
    <link rel="stylesheet" href="./style.css">
    <title>5.18 포스팅</title>
</head>

<body>
    <div>
        <h1>TodoList</h1>
        <button id="addBtn">add list</button>
    </div>

    <ul id="todoList">
        <li id="list1">
            리스트 1
        </li>
        <li id="list2">
            리스트 2
        </li>
        <li id="list3">
            리스트 3
        </li>
    </ul>
</body>
<script src="./index.js"></script>

</html>

CSS

//css
h1 {
  margin-bottom: 30px;
  font-size: 30px;
}

button {
  border: 0;
  outline: none;
  margin-bottom: 20px;
  margin-left: 20px;
  font-size: 14px;
  padding: 10px 20px;
  border-radius: 5px;
  color: black;
  cursor: pointer;
  font-weight: 800;
}

ul,
li {
  margin: 0;
  padding: 0;
}
li {
  list-style: none;
  border: 1px solid #eee;
  background: yellow;
  padding: 30px;
  font-size: 12px;
  margin-bottom: 10px;
  cursor: pointer;
}
li.remove {
  text-decoration: line-through;
}

JS

//index.js

const addBtn = document.getElementById("addBtn")
addBtn.addEventListener("click", addList)

// 추가 리스트 생성
function addList() {
  const ul = document.getElementById("todoList")
  const li = document.createElement("li")
  let listOrder = ul.children.length + 1
  li.setAttribute("id", "list" + listOrder)
  li.appendChild(document.createTextNode("추가 리스트 " + listOrder))
  ul.appendChild(li)
}

//리스트 삭제
let lists = document.querySelectorAll("li")
lists.forEach(function (li) {
  li.addEventListener("click", deleteList)
})

function deleteList() {
  const id = event.target.id
  document.getElementById(id).classList.toggle("remove")
}

이런식의 페이지가 구성이된 것을 확인하실 수 있어요.
여기서 리스트 요소를 클릭하면 리스트 요소가 삭제될 것이고, add list 버튼을 클릭할 시에는 '추가 리스트' 라는 항목이 추가될 것입니다.
그렇지만 우리가 원하던 대로 작동하지 않는 점이 있을거예요.

위의 gif파일을 보시면 아시겠지만, 기존에 있었던 리스트 들에 대해서는 삭제가 작동하지만, 추가된 리스트는 삭제되지 않고 있는 것을 보실 수 있어요.

그 이유는 li에 이벤트 리스너를 추가하는 시점에 기존에 있던 3개의 리스트만 등록되고, 새롭게 동적으로 추가된 리스트에는 이벤트 리스너가 등록되지 않았기 때문입니다.

우리는 event delegation을 통해서 이러한 현상을 해결해줄 수 가 있어요!

event delegation 적용

delegation이라는 단어의 뜻이 '위임'이죠?
이름과 같이 Event Delegation 이란 동적으로 노드를 생성하고 삭제할 때 각 노드에 대해 이벤트를 추가 하지 않고, 상위 노드에 그 이벤트를 위임하여 하위 노드의 이벤트를 제어 하는 방식을 말합니다.

적용방법은 간단해요. 이론 그대로 상위 노드에 해당 이벤트를 쥐어주면 되는 것이기 때문이죠.

//index.js
const addBtn = document.getElementById("addBtn")
addBtn.addEventListener("click", addList)

function addList() {
  const ul = document.getElementById("todoList")
  const li = document.createElement("li")
  let listOrder = ul.children.length + 1
  li.setAttribute("id", "list" + listOrder)
  li.appendChild(document.createTextNode("추가 리스트 " + listOrder))
  ul.appendChild(li)
}

// 리스트 삭제 기능
// let lists = document.querySelectorAll("li")
// lists.forEach(function (li) {
//   li.addEventListener("click", deleteList)
// })

//event delegation 사용
let lists = document.getElementById("todoList") //sampleId를 select
lists.addEventListener("click", deleteList)

function deleteList() {
  const id = event.target.id
  document.getElementById(id).classList.toggle("remove")
}

위에서 li 태그를 가져와서 이벤트를 주었던 것과 달리 그 상위 태그인 ul에다가 이벤트를 부여해주었습니다.
이제 어떻게 작동할까요?

우리가 처음에 생각했던대로 추가된 리스트에 대해서도 삭제기능이 잘 작동되는 것을 확인할 수 있습니다:)

event delegation의 장단점

event delegation을 사용해서 얻을 수 있는 장단점들은 다음과 같습니다.

장점

  • 각 하위 항목에 이벤트 핸들러를 연결하지 않고, 상위 요소에 하나의 단일 핸들러만 필요하기 때문에 메모리 사용 공간을 줄일 수 있습니다.
  • 제거된 요소에서 핸들러를 해제하고 새 요소에 대해 이벤트를 바인딩할 필요가 없습니다.

단점

  • 이벤트 위임을 사용하려면 이벤트가 반드시 버블링 되어야 합니다. 하지만 버블링이 되지 않는 이벤트도 몇몇 존재합니다.
  • 매우 낮은 레벨에 할당한 핸들러엔 event.stopPropagation()를 쓸 수 없습니다.

🙌 마무리

오늘은 이벤트 delegation에 대해 알아보았는데요.
어려운 개념은 아니지만 알고 있으시면 분명 도움이 될 것이라 생각합니다.
읽어주셔서 감사합니다:)

profile
김용성입니다.

0개의 댓글