피리부는 사나이 (pied piper)

[JS] 이벤트 핸들러 3가지와 이벤트 위임 (Event Delegation) 본문

Java Script

[JS] 이벤트 핸들러 3가지와 이벤트 위임 (Event Delegation)

코더 451 2022. 5. 3. 17:47

이벤트 핸들러

: 이벤트가 발생했을 때 브라우저에 호출을 위임한 함수.

 

1. 이벤트 핸들러 어트리뷰트 방식

: HTML 요소의 어트리뷰트 중에 이벤트에 대응하는 핸들러 어트리뷰트 값으로 함수 호출문 등의 statement를 할당하면 핸들러 등록 됨

 

 <button onclick="sayHi('Lee')" > CLick me!</button>

<script>
	function sayHI(name) {
		console.log(`Hi ${name}.`);
};
</script>

하지만 HTML과 JS는 관심사가 다르므로 혼재하는 것보다 분리하는 것이 좋음.

그러므로 이 1번 방식은 사용하지 않는 것이 더 좋음

 

 

2.이벤트 핸들러 프로퍼티 방식 

 

: window 객체와 Document, HTMLElement 타입의 DOM 노드 객체는 이벤트에 대응하는 핸들러 프로퍼티를 가지고 있음. 프로퍼티에 함수를 바인딩하면 이벤트 핸들러 등록 됨

 

const $button = document.querySelector('button');

$button.onclick = function () {
	console.log('button click');
};

핸들러를 등록하기 위해서는 이벤트를 발생시킬 객체인 event target과 이벤트의 종류를 나타내는 문자열인

event type, 이벤트 핸드러를 지정해야 함.

 

 

3. addEventListener 메서드 방식 

: DOM 레벨 2에서 도입된 EventTarget.prototype.addEventListener 메서드를 사용해서

이벤트 핸들러를 등록 가능. 1번과 2번은 레벨 0부터 제공된 방식

 

 

이 메서드의 장점은 기존 프로퍼티 방식은 하나 이상의 이벤 핸드러를 등록할 수 없지만 하나 이상의 이벤 핸들러를 등록 가능 (등록된 순서대로 호출)

 

 

이벤트 핸들러 제거 :
addEventListener로 등록한 이벤트 핸드러를 제거하려면 removeEventListener를 사용하면 된다.
이 메서드에 전달할 인수는 addEventListener와 동일하다.
(일치 하지 않으면 이벤트 핸들러 제거 X)

 

 


이벤트 전파 

:DOM 트리 상에 존재하는 DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파.

 

<예시>

<ul id="fruits">
	<li id="apple">Apple</li>
	<li id="banana">Banana</li>
	<li id="orange">Orange</li>
</ul>
ul 요소의 두 번째 자식 요소인 li요소를 클릭하면 클릭 이벤트 발생.
이때 생성된 이벤트 객체는 이벤트를 발생시킨 DOM 요소인 eventTarget을 중심으로 DOM트리를 통해 전파.
이벤트 객체가 전파되는 영향에 따라
3단계로 구분

 

 

  1. 캡쳐링 단계 : 이벤트가 상위 요소에서 하위 요소 방향으로 전파
  2. 타깃 단계 : 이벤트가 이벤트 타깃에 도달
  3. 버블링 단계 : 이벤트가 하위요소에서 상위 요소 방향으로 전파

예를 들어, ul요소에 이벤트 핸들러를 바인당하고 하위 요소인 li 요소를 클릭하여 이벤트 발생 시킨다면,

이때 event.target은 ‘li’요소이고 eventcurrentTarget은 ul 요소가 됨

 

 

 

<예제>

<ul id="fruits"> //current.Target
	<li id="apple">Apple</li>
	<li id="banana">Banana</li> //event.Target 
	<li id="orange">Orange</li>
</ul>



$fruits.addEventListener('click', e => {

	console.log(`이벤트 단계 : ${e.eventPhase}` ); // 3: 버블링
	console.log(`이벤트 타깃 : ${e.target}` ); // [object HTMLElement]
	console.log(`이벤트 타깃 : ${e.currentTarget}`); // [object HTMLEUlistElement]
  1. 'li’ 요소를 클릭하면 클릭 이벤트가 발생하여 클릭 이벤트 객체 생성 => li 요소가 eventTarget 됨
  2. 클릭 이벤트 객체는 window에서 시작해서 eventTarget 방향으로 전파 (캡처링 단계)
  3. 이벤트 객체는 이벤트를 발생시킨 eventTarget에 도달 (타깃 단계)
  4. 이벤트 객체는 이벤트 객체에서 시작해서 window 방향으로 전파 (버블링 단계)

 

 

 

 

 

 


이벤트 위임 (Event Delegation)

: 여러 개의 하위 DOM 요소에 각각 이벤트 핸들러를 등록하는 대신 하나의 상위 DOM 요소에 이벤트 핸들러를

등록하는 방법

 

이것을 이용하면 상위 DOM요소에 이벤트 핸들러 등록으로 여러 개의 하위 DOM 요소에 이벤트 핸들러를 여러 개 따로 등록할 필요가 없음.

 

ul의 하위 요소인 li에 일일이 리스너를 달아주는 방식은 너무 번거롭고 비효율적이다.
상위 DOM 요소인 ul에 하나의 핸들러만 등록하는 이벤트 위임 방식을 쓰자

 

<예제>

 

<ul id="fruits"> //current.Target
	<li id="apple">Apple</li>
	<li id="banana">Banana</li> //event.Target 
	<li id="orange">Orange</li>
</ul>
<div> <em class="msg">apple</em></div> // 선택된 내비게이션 아이템


<script>

const fruits = document.getElementById('fruits');
const msg = document.getElementById('msg');


function activate ({target}) {

 if(!target.matches(#fruits > li)) return;
[...$fruit.classList.toggle('active', $fruit === target);
	  $msg.textContent = target.id;
});

}

$fruits.onclick = activate;


</script>

이벤트 위임을 통해 하위 DOM 요소에 발생한 이벤트 처리 할 때 주의점은 상위 요소에 이벤트 핸들러를 등록하기 때문에

이벤트 타깃, 즉 이벤트를 실제로 발생시킨 DOM 요소가 개발자가 기대한 DOM 요소가 아닐 수 있음.

따라서 이벤트에 반응이 필요한 DOM 요소에 한정하여 실행되도록 eventTarget을 검사해야 함

 

 

*Element.prototype.matches 메서드 : 인수로 전달된 선택자에 의해 특정 노드 탐색 가능한지 확인

 

 

function activate ({target}) {
if (!target.matches('#fruits > li')) return;
...
//이벤트를 발생시킨 요소(타깃)이 ul#fruits의 자식요소 아니면 무시

일반적으로 이벤트 객체의 target 프로퍼티와 currentTarget 프로퍼티는 동일한 DOM 요소를 가리키지만

이벤트 위임을 통해 상위 DOM 요소에 이벤트 바인딩 한 경우

이벤트 객체의 target 프로퍼티와 currentTarget 프로퍼티가 다른 DOM 요소 가리킬 수 있음

위의 예제는 $fruits요소에 이벤트 바인딩 함.

 

<예제>

$fruits.onclick = activate;

이떄 이벤트 객체의 currentTarget 프로퍼티는 변함없이 $fruits 요소 가리키지만,

이벤트 객체의 target 프로퍼티는 실제로 이벤트를 발생시킨 DOM 요소를 가리킴.

$fruits 요소도 클릭 이벤트를 발생시킬 수 있으므로 이 경우 이벤트 객체의 currentTarget 프로퍼티와

target 프로퍼티는 동일한 $fruits를 가리키지만 $fruits 요소의 하위 요소에 클릭 이벤트가 발생한 경우

이벤트 객체의 currentTarget 프로퍼티와 target 프로퍼티는 다른 DOM 요소를 가리킴

Comments