Event 객체는 이벤트를 발생시킨 요소와 발생한 이벤트에 대한 유용한 정보들을 제공한다. 이벤트가 발생하면 Event 객체는 동적으로 생성되며 이벤트를 처리할 수 있는 이벤트 핸들러에 인자로 전달된다.
<!DOCTYPE html>
<html>
<body>
<p>클릭한 곳의 좌표가 표시됩니다.</p>
<script>
function showCoords(e) { // e: event object
console.log('clientX value: ', e.clientX); // 254
console.log('clientY value: ', e.clientY); // 28
}
addEventListener('click', showCoords); // 참조하는 게 없으면 target은 기본 window 전역 객체
</script>
</body>
</html>
위와 같이 Event 객체는 이벤트 핸들러에 암묵적으로 전달된다. 그러나 이벤트 핸들러를 선언할 때 event 객체를 전달 받을 첫 번째 매개변수를 명시적으로 선언해야 한다(위 예시에서의 e).
Event 객체 속성 종류
Event.target
실제로 이벤트를 발생시킨 요소를 가리킨다. 단, 버블링에 의해 쌩뚱맞는 다른 target이 인식될 수도 있다.
Event.currentTarget
코드에서 이벤트에 바인딩된 DOM 요소를 가리킨다. 즉 addEventListener 앞에 기술된 객체를 가리키는 것. 따라서 이벤트 핸들러 함수 내 currentTarget과 this는 언제나 일치한다.
예를 들어 아래 예시에서는 <div>를 이벤트 리스너로 등록했다. 그러나 <div> 안에 <button>이 있는데 <div> 영역을 클릭하든 <button> 영역을 클릭하든 똑같이 이벤트가 발생하는 것이다.
this: <div>
e.target: <button>
e.currentTarget: <div>
<div>
<button>배경색 변경</button>
</div>
document.querySelector('div').addEventListener('click', function() {
// this: 이벤트에 바인딩된 DOM 요소(div 요소)
console.log('this: ', this);
// target: 실제로 이벤트를 발생시킨 요소(button 요소 또는 div 요소)
console.log('e.target:', e.target);
// currentTarget: 이벤트에 바인딩된 DOM 요소(div 요소)
console.log('e.currentTarget: ', e.currentTarget);
});
Event.type
발생한 이벤트의 종류를 나타내는 문자열을 반환한다.
addEventListener('click', (e) => { // 참조하는 게 없으면 target은 기본 window 전역 객체
console.log(e.type); // click
})
Event.cancelable
요소의 기본 동작을 취소시킬 수 있는지 여부(true/false)를 나타낸다.
Event.eventPhase
이벤트 흐름(event flow)상에서 어느 단계(event phase)에 있는지 반환한다.
반환 값 | 의미 |
0 | 이벤트 없음 |
1 | 캡처링 단계 |
2 | 타깃 |
3 | 버블링 단계 |
Event Delegation(이벤트 위임)
일반적으로 모든 <li> 요소가 클릭 이벤트에 반응하는 처리를 구현하고 싶은 경우 <li> 요소에 이벤트 핸들러를 바인딩하면 총 5개의 이벤트 핸들러를 바인딩해야 한다.
<ul id="post-list">
<li id="post-1">Item 1</li>
<li id="post-2">Item 2</li>
<li id="post-3">Item 3</li>
<li id="post-4">Item 4</li>
<li id="post-5">Item 5</li>
</ul>
function printId() {
console.log(this.id);
}
document.querySelector('#post-1').addEventListener('click', printId);
document.querySelector('#post-2').addEventListener('click', printId);
document.querySelector('#post-3').addEventListener('click', printId);
document.querySelector('#post-4').addEventListener('click', printId);
document.querySelector('#post-5').addEventListener('click', printId);
만약 <li>가 100개라면 100번의 이벤트 핸들러를 바인딩해야 한다. 이는 실행 속도 저하의 원인이 될 뿐만 아니라 코드 또한 매우 길어지며 작성도 불편하다. 그리고 동적으로 <li> 요소가 추가되는 경우 아직 추가되지 않은 요소는 DOM에 존재하지 않으므로 이벤트 핸들러를 바인딩할 수 없다.
이러한 경우 이벤트 위임(Event Delegation)을 사용한다. 이벤트 위임은 다수의 자식 요소에 각각 이벤트 핸들러를 바인딩하는 대신 하나의 부모 요소에 이벤트 핸들러를 바인딩하는 방법이다.
위 예시의 경우라면 5개의 자식 요소에 각각 이벤트 핸들러를 바인딩하는 것 대신 부모 요소(ul#post-list)에 이벤트 핸들러를 바인딩하는 것이다. 또한 DOM 트리에 새로운 <li> 요소를 추가하더라도 이벤트 처리는 부모 요소인 ul 요소에 위임되었기 때문에 새로운 요소에 이벤트 핸들러를 다시 바인딩할 필요가 없다. 이는 이벤트가 이벤트 흐름에 의해 이벤트를 발생시킨 요소의 부모 요소에도 영향(버블링)을 미치기 때문에 가능한 것이다.
따라서 아래 예시에서 부모 요소 <ul>에 이벤트를 바인딩한 후 <li id="post-3">을 클릭한 결과는 다음과 같다(실제로 이벤트를 발생시킨 요소를 알아내기 위해서는 Event.target을 사용한다).
<ul id="post-list">
<li id="post-1">Item 1</li>
<li id="post-2">Item 2</li>
<li id="post-3">Item 3</li>
<li id="post-4">Item 4</li>
<li id="post-5">Item 5</li>
</ul>
<script>
const list = document.querySelector('ul#post-list')
list.addEventListener('click', function (e) {
// 이벤트를 발생시킨 요소
console.log('[target]: ' + e.target); //<li id='post-3'></li>
// 이벤트를 발생시킨 요소의 nodeName
console.log('[target.nodeName]: ' + e.target.nodeName); // LI
// li 요소 이외의 요소에서 발생한 이벤트는 대응하지 않는다.
if (e.target && e.target.nodeName === 'LI') {
console.log('li#' + e.target.id + ' was clicked!'); // li#post-3 was clicked!
}
});
</script>
'Javascript > Javascript' 카테고리의 다른 글
[Javascript] console 사용 시 쉼표(,)와 +의 차이 (0) | 2024.10.22 |
---|---|
[Javascript] 이벤트 캡처링 (0) | 2024.10.21 |
[Javascript] 이벤트 핸들러와 this (0) | 2024.10.16 |
[Javascript] Event의 종류 (2) | 2024.10.15 |
[Javascript] Array 함수 (0) | 2024.10.10 |