HTML 요소의 속성 중에는 이벤트에 대응하는 이벤트 핸들러 속성이 있다. 이벤트 속성의 이름은 onclick
과 같이 on
접두사와 이벤트의 종류를 나타내는 이벤트 타입으로 이루어져 있다.
이벤트 핸들러 속성 값으로 함수 호출문 등의 문(statement)을 할당하면 이벤트 핸들러가 등록된다.
여러개의 핸들러 할당이 불가능하다.
HTML 속성을 이용한 이벤트 핸들러 할당은 자주 쓰이지 않는다. HTML 태그 중간에 자바스크립트가 들어가 있으면 어색하기 때문이다. 긴 코드를 끼워 넣는 게 불가능한 점도 이유 중 하나이다.
주의할 점은 이벤트 핸들러 속성 값으로 함수 참조가 아닌 함수 호출문
을 할당하는 것이다.
함수 참조 VS 함수 호출
- 함수 참조 :
func
- 함수 호출 :
func()
// input 태그의 onclick 속성에 click 핸들러를 할당
<input value="클릭해 주세요." onclick="alert('클릭!')" type="button">
// HTML 속성값으로 긴 코드가 들어가야 한다면, 함수를 만들어서 호출하는 방법을 사용한다.
// 아래 버튼을 클릭하면 countRabbits 함수가 호출된다.
<input type="button" onclick="countRabbits()" value="토끼를 세봅시다!">
<script>
function countRabbits() {
for(let i=1; i<=3; i++) {
alert(`토끼 ${i}마리`);
}
}
</script>
위 예제와 같이 함수 호출문을 할당하게 될 경우, 이때 이벤트 핸들러 속성 값은 사실 암묵적으로 생성될 이벤트 핸들러의 함수 몸체를 의미한다.
이벤트 핸들러 속성 값은 파싱되어 아래와 같은 함수를 암묵적으로 생성하고, 이벤트 핸들러 속성 이름과 통일한 onclick
이벤트 핸들러 프로퍼티에 할당한다.
function onclick(event) {
countRabbits();
}
DOM 프로퍼티의 키는 HTML 속성 방식과 마찬가지로 onclick과 같이 on
접두사와 이벤트의 종류를 나타내는 이벤트 타입으로 이루어져 있다.
이벤트 핸들러 프로퍼티에 함수를 바인딩(메서드와 객체를 묶어놓는 것)하면 핸들러가 등록된다.
여러개의 핸들러 할당이 불가능하다.
HTML 속성 방식도 결국 DOM 노드 객체의 이벤트 핸들러 프로퍼티로 변환되므로 DOM 프로퍼티 방식과 동일하다고 할 수 있다.
이벤트 핸들러를 등록하기 위해서는 이벤트를 발생시킬 객체인 이벤트 타겟(event target)과 이벤트의 종류를 나타내는 문자열인 이벤트 타입(event type) 그리고 이벤트 핸들러를 지정해야 한다.
<input type="button" id="button" value="클릭해 주세요.">
<script>
button.onclick = function() {
alert('클릭!');
};
</script>
onclick = null
같이 null을 할당한다.// 아래와 같이 핸들러를 하나 더 추가하면, 기존 핸들러는 덮어 씌워진다.
// HTML 속성에 할당한 alert('이전') 창은 뜨지 않고 스크립트의 alert('이후') 창만 뜬다.
<input type="button" id="elem" onclick="alert('이전')" value="클릭해 주세요.">
<script>
elem.onclick = function() { // 기존에 작성된 핸들러를 덮어씀
alert('이후'); // 이 alert창만 보인다.
};
</script>
addEventListner
라는 메서드를 사용한다.
- 기본 문법
EventTarget.addEventListener(eventType, eventHandler, [options]);
- 매개변수
- eventType : 이벤트 이름(ex : "click"), (
on
접두사를 붙이지 않는다)- eventHandler : 이벤트 핸들러 함수명
- options : 아래 프로퍼티를 갖는 객체
once
:true
이면 이벤트가 트리거 될 때 리스너가 자동으로 삭제된다.capture
: 어느 단계에서 이벤트를 다뤄야 하는지를 알려주는 프로퍼티로, 버블링과 캡쳐링이 있다. 호환성 유지를 위해options
를 객체가 아닌true/false
로 할당하는 것도 가능한데, 이는{capture: true/false}
와 동일하다.passive
:true
이면 리스너에서 지정한 함수가preventDefault()
를 호출하지 않는다.
addEventListner
를 여러 번 호출하면 아래와 같이 핸들러를 여러 개 붙일 수 있다.<input id="elem" type="button" value="클릭해 주세요.">
<script>
function handler1() {
alert('첫 번째 출력!');
};
function handler2() {
alert('두 번째 출력!');
}
elem.addEventListener("click", handler1); // '첫 번째 출력!' alert창 출력
elem.addEventListener("click", handler2); // `두 번째 출력!` alert창 출력
</script>
addEventListner
메서드로 등록한 이벤트를 제거하려면 removeEventListner
메서드를 사용한다.
removeEventListner
메서드에 전달할 인수는 addEventListner
메서드와 동일하지만, addEventListner
메서드에 전달한 인수와 removeEventListner
메서드에 전달한 인수가 동일하지 않으면 이벤트 핸들러가 제거되지 않는다.
// 아래와 같이 이벤트를 할당하고 삭제해도 핸들러는 지워지지 않는다.
elem.addEventListener('click', function() {
alert('감사합니다!');
}
elem.removeEventListener('click', function() {
alert('감사합니다!');
}
// 위 예제를 아래와 같이 함수를 변수에 할당해서 수정하면 정상적으로 핸들러가 삭제된다.
let handler = function() {
alert( '감사합니다!' );
}
input.addEventListener("click", handler);
input.removeEventListener("click", handler); // 이벤트 핸들러가 제거 된다.
<input type="button" id="btn1" value="Hello">
<input type="button" id="btn2" value="Bye">
<script>
// Hello 버튼 이벤트
let helloBtn = document.querySelector("#btn1");
let clickListener = function() {
alert('Hello World!');
};
helloBtn.addEventListener('click', clickListener);
// Bye 버튼 이벤트
let byeBtn = document.querySelector("#btn2");
byeBtn.addEventListener('click', function() {
helloBtn.removeEventListener('click', clickListener);
});
</script>