"위임" 의 의미를 먼저 생각해보자.
인간 세상에서의 권한 위임이라 하면 보통 권한을 가진 윗사람(?)이 아랫사람(?)에게 하는 것으로 생각되지만, 우리가 알아볼 DOM 세상에서는 그 반대이다.
일반적으로 이벤트의 처리권한은 해당 이벤트가 일어난 DOM(이벤트 타겟)에 있기 때문이다.
🧳 Event Delegation은 아랫DOM(?)이 윗DOM(..)에게 이벤트를 대신 처리해달라고 위임하는 것을 의미한다.
<outer onclick={function (e) { console.log(`${e.target}이 클릭되었다!`) }}>
윗돔
<inner>아랫돔1</inner>
<inner>아랫돔2</inner>
<inner>아랫돔3</inner>
</outer>
이런 상황에서는 윗돔이 아랫돔들의 클릭 이벤트를 대신 처리해줄 수 있게 된다. 이것이 이벤트 위임이다.
여러모로 관리가 편해진다. 개발자들은 반복을 줄이는 쪽으로 코드를 작성하고 싶기 마련이다. 코드 상으로도 그렇지만, 이벤트 위임은 컴퓨터도 이벤트 핸들러를 반복적으로 등록하지 않아도 되도록 만들어주는 코딩 패턴이다.
위 예제를 예로 들면, 아랫돔들이 백만개로 늘어나면 이벤트 핸들러를 백만번 등록해주어야 한다.
백만개를 감싸고 있는 엘리먼트에 이벤트(처리)를 위임하면, 한개의 이벤트 핸들러로 모든 이벤트를 처리할 수 있게 된다!
🧳 이벤트를 관리하는 대형 프랜차이즈 본사(?)를 만드는 것이라고 생각하면 어떨까..
꼭 공통된 이벤트만을 위임하지 않아도 된다.
이벤트 위임을 조금 더 활용도 높게 사용하려면 아래와 같이 dataset 프로퍼티를 사용해 각각의 DOM에 키워드를 부여하고, 이 키워드들을 이용해 이벤트 핸들링을 casify 해줄 수 있다.
<html>
<body>
<div id="menu">
<button id="save" data-action="save">저장하기</button>
<button id="refresh" data-action="refresh">새로고침하기</button>
<button id="play" data-action="play">재생하기</button>
</div>
<script>
console.log(menu); // 따로 가져오지 않아도 element를 참조합니다.
/*
아래와 같이 클래스를 만들어주면
Menu와 관련된 함수들(Menu가 대리로 처리하는 여러개의 이벤트 핸들러)을
"하나의 관심사" 로 묶어서 표현 / 관리할 수 있습니다.
*/
class Menu {
constructor(elem) {
this._elem = elem; // menu 인스턴스의 내부 프로퍼티(앞에 _를 붙였습니다)로 저장합니다.
/*
이벤트 리스너에서 this는 이벤트 타겟을 가리킵니다.
우리는 onClick 내부에서 this[action] 으로 인스턴스의 메서드를 참조해서 사용해야 하기 때문에,
this를 Menu 인스턴스로 바인딩 시켜줍니다.
*/
elem.onclick = this.onClick.bind(this);
}
save() {
console.log(this._elem);
alert("저장하기");
}
load() {
alert("저장하기");
}
search() {
alert("저장하기");
}
onClick(event) {
let action = event.target.dataset.action;
if (action) {
this[action]();
}
}
}
new Menu(menu);
</script>
</body>
</html>
참고자료