[하루 30분 모던 자바스크립트 딥 다이브] 이벤트 핸들러 등록 방식

이번 포스팅에서 이벤트 핸들러 등록 방식에 대해 알아봅시다

🤔이벤트 핸들러 어트리뷰트 방식

  • HTML요소의 어트리뷰트 중에는 이벤트에 대응하는 이벤트 핸들러 어트리뷰트가 있습니다.
  • 이벤트 핸들러 어트리뷰트 값으로 함수 호출문 등의 문을 할당하면 이벤트 핸들러가 등록됩니다.
<!--index.html-->
<!--...-->
<body>
	<button onclick="sayHi('Lee')">Click!</button>
	<script>
		function sayHi(name){
			console.log(`Hi ${name}!`)
		}
	</script>
</body>
<!--...-->
  • 주의할 점은 함수 참조가 아닌 함수 호출문 등의 “문”(statement)를 할당한다는 것이다.
  • 이 방식은 더 이상 사용하지 않는 것이 좋다. html과 js의 관심사가 다르므로 혼재하는 것 보다는 분리하는 것이 좋다.
  • 하지만 CBD(Component Based Development) 방식의 라이브러리는 이벤트 핸들러 어트리뷰트 방식으로 이벤트를 처리한다.
<!-- Angular -->
<button (click)="handleClick($event)">Click</button>

<!-- React -->
<button onClick={handleClick}>Click</button>

<!-- Svelte -->
<button on:click={handleClick}>Click</button>

<!-- Vue -->
<button v-on:click="handleClick($event)">Click</button>

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

  • window 객체와 Document, HTMLElement 타입의 DOM 노드 객체는 이벤트에 대응하는 이벤트 핸들러 프로퍼티를 가지고 있다.
  • on접두사와 이벤트의 종류를 나타내는 이벤트 타입으로 이루어져 있다.
  • 이벤트를 발생시킬 객체인 이벤트 타깃, 이벤트 종류를 나타내는 문자열인 이벤트 타입, 그리고 이벤트 핸들러를 지정할 필요가 있다
const $button = document.querySelector("#button");
$button.onclick = function(){console.log("click")}
//$button = 이벤트 타깃, onclikc = 이벤트 타입, function = 이벤트 핸들러
  • 프로퍼티 방식은 HTML과 JS의 혼용 문제를 해결할 수 있지만, 하나의 이벤트 핸들러만 바인딩 할 수 있다는 단점이 있다.
  • 이벤트 프로퍼티 방식으로 등록한 이벤트를 제거하려면 이벤트 핸들러 프로퍼티에 null값을 할당한다.
$button.onclick = function(){console.log("click")}
$button.onclick = null

🤔addEventListener 메서드 방식

  • DOM Level2에서 EventTarget.prototype.addEventListener 메서드를 사용하여 이벤트 핸들러를 등록할 수 있다. 앞서 살펴본 어트리뷰트 방식과 프로퍼티 방식은 DOM Level 0 부터 제공되던 방식이다.
EventTarget.addEventListener('eventType', functionName[, useCapture])
  • 첫 번째 매개변수로 이벤트의 종류, 두 번째 매개변수로 핸들러를, 세 번째 매개변수로 이벤트를 캐치할 전파 단계를 지정한다. 세번 째 매개변수를 생략하거나 false값을 지정하면 버블링 단계에서, 반대 상황에선 캡처링 단계에서 이벤트를 캐치한다.
const $button = document.querySelector("#button");
$button.addEventListener('click', function(){console.log("click")})
  • 이벤트 핸들러 프로퍼티에 바인딩 된 핸들러에는 아무런 영향을 끼치지 않아, 만약 버튼 요소에 프로퍼티에 핸들러를 바인딩하고, addEventListener 메서드로 핸들러를 등록한다면 2개의 이벤트가 모두 호출된다.
  • 이 방식 역시 여러개의 이벤트를 등록하는 것이 가능하다.
  • removeEventListener 메서드로 등록한 이벤트를 제거할 수 있다.
const $button = document.querySelector("#button");

function handler(){
	console.log("click")
}

$button.addEventListener('click', handler)
$button.removeEventListener('click', handler, true) //실패
$button.removeEventListener('click', handler) //성공
  • 이벤트 제거는 같은 핸들러를 참조하여야 제거되기 때문에 무명 함수를 사용한다면 제거하는 것이 불가능하다.
const $button = document.querySelector("#button");

$button.addEventListener('click', ()=>{console.log("click")})
$button.removeEventListener('click', ()=>{console.log("click")) //실패
  • 한 번만 이벤트 핸들러를 호출하기 위해선 다음과 같이 할 수 있다
const $button = document.querySelector("#button");

//기명 함수
$button.addEventListener('click', function foo(){
	console.log("click")
	$button.removeEventListener('click', foo);
})

//무기명 함수
//함수 자신을 가리키는 argument.callee를 사용하여 제거
$button.addEventListener('click', function (){
	console.log("click")
	$button.removeEventListener('click', arguments.callee);
})