이벤트위임

이벤트 위임

비슷한 방식으로 여러 요소를 다루어야 할때 사용한다.

공통 조상 이벤트 핸들러를 단 하난만 할당해도 여러 요소를 한꺼번에 다룰 수 있게 된다.

공통 종상에 할당한 이벤트 핸들러에서 event.target을 이용하면 실제 어디서 이벤트가 발생했는지 알 수 있다.

예를 들어 tabel 요소에 각 td에 다 이벤트 핸들러를 등록하는 것이 아니라 table 안에다가 이벤트를 등록하고 event.target으로 어떤 요소에 이벤트 가 발생했는지 확인하는 방식이 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let selectedTd;

table.onclick = function(event) {
let target = event.target; // 클릭이 어디서 발생했을까요?

if (target.tagName != 'TD') return; // TD에서 발생한 게 아니라면 아무 작업도 하지 않습니다,

highlight(target); // 강조 함
};

function highlight(td) {
if (selectedTd) { // 이미 강조되어있는 칸이 있다면 원상태로 바꿔줌
selectedTd.classList.remove('highlight');
}
selectedTd = td;
selectedTd.classList.add('highlight'); // 새로운 td를 강조 함
}

만약 td 안에 strong이라는 요소가 있어서 strong 요소를 클릭했다면 event.target은 strong 이 될 것이다.

이런 부분을 반영하여 코드를 고친다.

1
2
3
4
5
6
7
8
9
table.onclick = function(event) {
let td = event.target.closest('td'); // (1)

if (!td) return; // (2)

if (!table.contains(td)) return; // (3)

highlight(td); // (4)
};
  1. event.target.closet(selector)을 활용하여 elem의 상위 요소 중 selector와 일치하는 가장 근접한 조상 요소를 반환 함.
  2. 선택한 요소가 td 안에 없으면 null을 반환함.
  3. table 요소 밖에 td 요소를 선택했으면 return 함.
  4. 강조

이벤트 위임 활용하기

save, load, search 기능을 수행하는 버튼을 만든다고 했을때, 메뉴 전체에 핸들러를 하나 추가해주고, 각 버튼의 data-action 속성에 호출할 메서드를 할당해 주는 방법을 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<div id="menu">
<button data-action="save">저장하기</button>
<button data-action="load">불러오기</button>
<button data-action="search">검색하기</button>
</div>

<script>
class Menu {
constructor(elem) {
this._elem = elem;
elem.onclick = this.onClick.bind(this); // (*)
}

save() {
alert('저장하기');
}

load() {
alert('불러오기');
}

search() {
alert('검색하기');
}

onClick(event) {
let action = event.target.dataset.action;
if (action) {
this[action]();
}
};
}

new Menu(menu);
</script>

* onClick의 bind로 this를 주지 않으면 this 가 Menu 가 아닌 DOM 요소 elem을 참조하게 되서 this[action]을 사용할 수 없다.

장점?

  • 버튼마다 핸들러를 할당해주는 코드를 작성할 필요가 없어짐.
  • 언제든지 버튼을 추가하고 제거할 수 있어 html 구조가 유연해 짐.

행동 패턴

이벤트 위임은 요소에 선언적 방식으로 행동을 추가할 때 사용할 수 도 있다.

행동 패턴은 두 부분으로 구성됨.

  1. 요소의 행동을 설명하는 커스텀 속성을 요소에 추가
  2. 문서 전체를 감지하는 핸들러가 이벤트를 추적하게 함. 1에서 추가한 속성이 있는 요소에서 이벤트가 발생하면 작업을 수행함.

카운터 구현

버튼을 클릭하면 숫자가 증가하는 행동을 부여하는 속성인 data0counter를 살펴봄

1
2
첫 번째 카운터: <input type="button" value="1" data-counter>
두 번째 카운터: <input type="button" value="2" data-counter>
1
2
3
4
5
6
7
8
9
10

<script>
document.addEventListener('click', function(event) {

if (event.target.dataset.counter != undefined) { // 속성이 존재할 경우
event.target.value++;
}

});
</script>

문서 레벨의 핸들러를 만들 땐 항상 addEventListener를 사요할 것

토글러 구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<button data-toggle-id="subscribe-mail">
구독 폼 보여주기
</button>

<form id="subscribe-mail" hidden>
메일 주소: <input type="email">
</form>

<script>
document.addEventListener('click', function(event) {
let id = event.target.dataset.toggleId;
if (!id) return;

let elem = document.getElementById(id);

elem.hidden = !elem.hidden;
});
</script>