들어가며
- 이벤트 등록 방법
- 이벤트 전달 방식 (이벤트 버블링, 이벤트 캡쳐링, 이벤트 위임)
- event.stopPropagation()
이벤트 등록
이벤트 등록이란 웹 어플리케이션에서 사용자의 입력을 받기 위해 필요한 기능입니다.
1) 간단한 버튼을 만듭니다.
<button>add one item</button>
2) 버튼 클릭 시 addItem 함수를 실행되고, 이 때 event 인자가 넘어옵니다.
let button = document.querySelector('button');
button.addEventListener('click', addItem);
function addItem(event) {
console.log(event);
}
이처럼 addEventListener 같은 웹 API는 이벤트 등록을 가능하게 해줍니다.
이벤트 등록을 함으로써 얻는 효과는 사용자의 입력에 따라 추가 동작을 구현할 수 있다는 것입니다.
그렇다면 브라우저는 어떻게 이벤트의 발생을 감지했을까요?
이벤트 버블링
이벤트 버블링이란 HTML의 하위 요소에서 상위 요소로 해당 이벤트가 전달되는 것을 말합니다.
예제
<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
let divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
Output
three
two
one
div 태그 하나 클릭 시 3개의 이벤트가 발생합니다.
왜 그럴까요?
브라우저는 특정 요소에서 이벤트가 발생하면 해당 이벤트를
최상위에 있는 요소까지 이벤트를 전파시키는 동작 방식을 가지고 있기 때문이지요.
단, 전제조건은 각각 태그에 이벤트가 등록되어 있어야 합니다.
이벤트 캡쳐링
<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
let divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent, {
capture: true // default 값은 false
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
capture:true를 설정해주면 상위에서 하위 방향으로 이벤트를 탐색합니다.
위 코드 실행시, 아래와 같이 이벤트 버블링과 반대 결과가 출력됩니다.
Output
one
two
three
이벤트 위임 (Event Delegation)
이벤트 위임이란 캡처링과 버블링을 활용하는 이벤트 핸들링 패턴입니다.
이벤트 위임은 각 요소의 공통 조상에 이벤트 핸들러 단 하나를 할당하여 여러 요소를
한꺼번에 다루는 방식입니다.
<table>
<tr>
<th colspan="3"><em>Bagua</em> Chart: Direction, Element, Color, Meaning</th>
</tr>
<tr>
<td class="nw"><strong>Northwest</strong><br>Metal<br>Silver<br>Elders</td>
<td class="n">...</td>
<td class="ne">...</td>
</tr>
</table>
위 코드에는 3개의 <td> 가 있습니다.
하려고 하는 작업이 <td>를 클릭했을 때 그 칸을 강조되게 하는 것이라고 가정해봅시다.
각 <td>마다 onclick 핸들러를 할당하는 대신, 공통 상위요소인 <table>요소에 onclick을 할당하겠습니다.
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를 강조 함
}
event.target을 이용해 어떤 요소가 클릭되었는지 감지 하고, 해당 칸을 강조합니다.
table에 이벤트를 위임해두면 td가 몇개이든 상관없이 강조기능을 적용할 수 있습니다.
하지만 단점도 있습니다.
위 코드는 클릭 이벤트가 <td>가 아닌 <td>안에서 동작 할 수 있습니다.
<td>
<strong>Northwest</strong>
...
</td>
<strong> 클릭 시 event.target에 <strong> 해당 요소가 저장됩니다. 아래 코드를 통해 단점을 보완해보겠습니다.
table.onclick 핸들러에서 event.target을 이용해 클릭 이벤트가 <td> 안쪽에서 일어났는지
알아내야 합니다.
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.closest('td')는 event.target의 상위요소중 가장 근접한 'td'를 찾습니다.
2. event.target이 <td>안에 있지 않으면 즉시 null 반환하며, 아무 작업도 하지 않습니다.
3. 중첩 테이블이 있는 경우 event.target은 현재 테이블 바깥에 있는 <td>가 될 수 있음.
이런 경우를 대비해 <td>가 팔괘도 안에 있는지 점검.
4. td를 강조해준다.
이벤트 위임의 이점
1. 동적인 엘리먼트에 대한 이벤트 처리가 수월하다. (추가되고 삭제되는 요소들)
2. 효율적인 이벤트 핸들러 관리. 상위 엘리먼트에서만 이벤트 리스너를 관리하기 때문에
3. 메모리 사용량 줄어듦
4. 메모리 누수 가능성 줄어듦
*메모리 누수(memory leak) 현상은 컴퓨터 프로그램이 필요하지 않은 메모리를 계속 점유하고 있는 현상이다
event.stopPropagation()
stopPropagation() 웹 API는 이벤트 전파를 막습니다.
이벤트 버블링의 경우 클릭한 요소의 이벤트만 발생시킵니다. 위로 전파하지 않습니다.
반면 이벤트 캡쳐링의 경우에는 클릭한 요소의 최상위 요소의 이벤트만 발생시킵니다. 아래로 전파하지 않습니다.
예시
<div class="three"> 클릭시
<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
// 이벤트 버블링
divs.forEach(function(div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
event.stopPropagation();
console.log(event.currentTarget.className); // three
}
Output (해당 클릭요소만 이벤트 발생)
three
// 이벤트 캡쳐
divs.forEach(function(div) {
div.addEventListener('click', logEvent, {
capture: true // default 값은 false입니다.
});
});
function logEvent(event) {
event.stopPropagation();
console.log(event.currentTarget.className); // one
}
Output (클릭한 이벤트의 최상위요소 이벤트 발생)
one
Ref
ui.toast.com/weekly-pick/ko_20160826/
www.javascripttutorial.net/javascript-dom/javascript-events/
ko.javascript.info/event-delegation
joshua1988.github.io/web-development/javascript/event-propagation-delegation/
'프론트엔드 > Javascript' 카테고리의 다른 글
JavaScript- require vs import (CommonJs와 ES6) 차이점 (0) | 2020.10.30 |
---|---|
실행 컨텍스트 정리 (0) | 2020.10.23 |
자바스크립트의 동시성을 지원하는 이벤트루프 (0) | 2020.10.21 |
비동기 처리하는 3가지 방법 (0) | 2020.10.19 |
싱글스레드 자바스크립트 (0) | 2020.10.16 |