언어/자바스크립트
자바스크립트 5 - 이벤트
SuhyeokRoh
2024. 4. 15. 17:59
이벤트(Event)
프로그래밍하는 시스템에서 일어나는 사건(action) 혹은 발생(occurrence)
- 애플리케이션이 특정 타입의 이벤트에 대해 반응하여 어떤 일을 하고 싶다면 해당하는 타입의 이벤트가 발생했을 때 호출된 함수를 브라우저에 알려 호출을 위임할 수 있음
- 이벤트 핸들러(Event Handler) : 이벤트가 발생했을 때 호출될 함수
- 이벤트 핸들러 등록 : 이벤트가 발생했을 때 브라우저에 이벤트 핸들러의 호출을 위임하는 것
이벤트 타입
- 이벤트 타입은 약 200여 가지가 존재
- 그 중 사용 빈도가 높은 이벤트로는 마우스 이벤트, 키보드 이벤트, 포커스 이벤트, 폼 이벤트(form event), 값 변경 이벤트, DOM 뮤테이션 이벤트, 뷰 이벤트, 리소스 이벤트가 존재
상세 목록은 MDN 사이트 참고(https://developer.mozilla.org/en-US/docs/Web/Events)
이벤트 핸들러 등록
1. 이벤트 핸들러 어트리뷰트 방식
- HTML 요소의 어트리뷰트 중 이벤트에 대응하는 이벤트 핸들러 어트리뷰트가 존재함
- 이름은 on 접두사와 이벤트 종류를 나타내는 이벤트 타입으로 이루어짐 (ex. onClick)
- 이벤트 핸들러 어트리뷰트 값으로 함수 참조가 아닌 함수 호출문 등의 문(statement)을 할당하면 이벤트 핸들러가 등록됨
<!DOCTYPE html> <html> <body> <button onclick="sayHi('Lee')">Press me</button> <script> function sayHi(name) { console.log(`Hi, ${name}.`); } </script> </body> </html>
- 이 방식은 HTML과 자바스크립트가 혼재되어 있어 사용하지 않는 것이 좋음
- 하지만 컴포넌트 기반 개발(CBD) 방식의 Angular / React / Svelte / Vue.js 같은 프레임워크 / 라이브러리에서는 이벤트 핸들러 어트리뷰트 방식으로 이벤트를 처리
2. 이벤트 핸들러 프로퍼티 방식
- DOM 노드 객체는 이벤트에 대응하는 이벤트 핸들러 프로퍼티가 존재함
- 프로퍼티의 키는 이벤트 핸들러 어트리뷰트처럼 on 접두사와 이벤트 타입으로 구성
- 이벤트 핸들러 프로퍼티에 함수를 바인딩하면 이벤트 핸들러가 등록됨
<!DOCTYPE html> <html> <body> <button>Press me</button> <script> const $button = document.querySelector('button'); //$button : 이벤트 타깃, onClick : 이벤트 타입, function ~ : 이벤트 핸들러 $button.onClick = function() { console.log('button click'); }; </script> </body> </html>
- 이벤트 핸들러 등록을 위해서는 이벤트를 발생시킬 객체인 이벤트 타겟(Event target)과 이벤트의 종류를 나타내는 문자열인 이벤트 타입(Event type), 이벤트 핸들러를 지정해야 함
- 이 방식으로 HTML과 자바스크립트가 섞이는 문제를 해결할 수 있지만, 이벤트 핸들러 프로퍼티에 하나의 이벤트 핸들러만 바인딩할 수 있다는 단점이 존재
3. addEventListener 메서드 방식
- DOM Level 2에서 도입된 addEventListener 메서드를 사용해 이벤트 핸들러를 등록할 수 있음
EventTarget.addEventListener('eventType', functionName [, useCapture]);
<!DOCTYPE html> <html> <body> <button>Press me</button> <script> const $button = document.querySelector('button'); $button.addEventListener('click', function() { console.log('button click'); }); </script> </body> </html>
- 첫 번째 매개변수 : 이벤트 종류를 나타내는 문자열인 이벤트 타입을 전달
- on 접두사를 붙이지 않음
- 두 번째 매개변수 : 이벤트 핸들러를 전달
- 마지막 매개변수 : 이벤트를 캐치할 이벤트 전파 단계(캡처링(capturing) or 버블링(bubbling))을 지정
- addEventListener 메서드는 동일한 HTML에 하나 이상의 이벤트 핸들러를 등록할 수 있음
- 참조가 동일한 이벤트 핸들러를 중복 등록하면 하나의 이벤트 핸들러만 등록
- 동일한 HTML 요소에 이벤트 핸들러 프로퍼티 방식, addEventListener 방식을 모두 사용하여 이벤트 핸들러를 등록
- addEventListener 방식은 프로퍼티에 바인딩된 이벤트 핸들러에 영향을 주지 않음
- 따라서 2개의 이벤트 핸들러가 모두 호출됨
이벤트 객체
이벤트 발생 시, 동적으로 생성된 이벤트와 관련된 다양한 정보를 담고 있는 객체
- 생성된 이벤트 객체는 이벤트 핸들러의 첫 번째 인수로 전달됨
<!DOCTYPE html> <html> <body> <p>클릭 시, 클릭한 곳의 좌표가 표시</p> <em class="message"></em> <script> const $msg = document.querySelector('.msg'); function.showCoors(e) { $msg.textContent = `clientX: ${e.clientX}, clientY: ${e.clientY}`; }); document.onClick = showCoords; </script> </body> </html>
- 이벤트에 의해 생성된 이벤트 객체는 이벤트 핸들러의 첫 번째 인수로 전달되어 매개변수 e에 암묵적으로 할당됨
- 이벤트 핸들러를 정의할 떄, 이벤트 객체를 전달받을 매개변수를 명시적으로 선언해야 전달받을 수 있음
- 매개변수의 이름은 다른 이름이여도 상관 없음
※ 이벤트 핸들러 어트리뷰트 방식으로 이벤트 핸들러 등록 시, event라는 이름으로만 이벤트 객체를 전달받을 수 있음
-> 이벤트 핸들러 어트리뷰트 값은 암묵적으로 생성되는 이벤트 핸들러의 함수 몸체를 의미
-> 어트리뷰트는 파싱되어 아래와 같은 함수를 암묵적으로 생성, 이를 onClick 이벤트 핸들러 프로퍼티에 할당
function onClick(event) {
showCoords(event);
}
이벤트 객체의 공통 프로퍼티
Event 인터페이스에 정의되어 있는 이벤트 관련 프로퍼티는 모든 파생 이벤트 객체에 상속됨
공통 프로퍼티 | ||
type | 이벤트 타입 | string |
target | 이벤트를 발생시킨 DOM 요소 | DOM 요소 노드 |
currentType | 이벤트 핸들러가 바인딩된 DOM 요소 | DOM 요소 노드 |
eventPhase | 이벤트 전파 단계 | number |
bubbles | 이벤트 버블링 전파 여부 | boolean |
cancelable | 이벤트 기본 동작 취소 가능 여부 | boolean |
defaultPrevented | preventDefault 메서드를 통한 이벤트 취소 여부 |
boolean |
isTrusted | 사용자의 행위에 의해 발생한 이벤트인지 여부 |
boolean |
timeStamp | 이벤트가 발생한 시각 | number |
이벤트 전파
생성된 이벤트 객체는 이벤트를 발생시킨 DOM 요소인 이벤트 타겟을 중심으로 DOM 트리를 통해 전파
- 캡처링 단계(capturing phase) : 이벤트가 상위 요소에서 하위 요소 방향으로 전파
- 타깃 단계(target phase) : 이벤트가 이벤트 타깃에 도달
- 버블링 단계(bubbling phase) : 이벤트가 하위 요소에서 상위 요소 방향으로 전파
- 이벤트는 이벤트를 발생시킨 이벤트 타겟 뿐 아니라 상위 DOM 요소에서도 캐치할 수 있음
- DOM 트리를 통해 전파되는 이벤트는 이벤트가 통과하는 DOM 트리 상의 경로에 위치한 모든 DOM 요소에서 캐치할 수 있음
- 대부분의 이벤트는 캡처링과 버블링을 통해 전파되지만 포커스 이벤트의 focus / blur, 리소스 이벤트의 load / unload / abort / error, 마우스 이벤트의 mouseenter / mouseleave 는 버블링을 통해 전파되지 않음