자바스크립트 이벤트 정리
이벤트
40.1 이벤트 드리븐 프로그래밍
브라우저는 처리해야할 사건이 발생하면 감지하여 이벤트를 발생 시킨다.
이벤트가 발생했을 때 호출될 함수를 이벤트 핸들러 라고 하고
이벤트가 발생했을 때 핸들러의 호출을 위임하는것을 이벤트 핸들러 등록 이라고 한다.
브라우저는 사용자의 버튼 클릭을 감지하여 클릭 이벤트를 발생시킬 수 있다. 그리고 요소에서
이벤트가 발생하면 특정 함수를 호출하도록 브라우저에게 위임 할 수 있다 .
이와 같이 프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식을 이벤트 드리븐 프로그래밍
이라고 한다 .
40.2 이벤트 타입
이벤트의 종류를 나타내는 문자열으로 약 200여가지가 있고
상세목록은 MDN 에서 확인 할 수 있다.
40.3 이벤트 핸들러 등록
이벤트 핸들러는 이벤트가 발생했을 때 브라우저에 호출을 위임한 함수다.
브라우저에 의해 호출될 함수가 이벤트 핸들러다.
핸들러등록은 총 3가지가 있다.
40.3.1 이벤트 핸들러 어트리뷰트 방식
이벤트에 대응하는 이벤트 핸들러 어트리뷰트가 있다. on접두사와 이벤트 타입을
붙여서 구현되어 있다 .
여기서 어트리뷰트 값으로 참조가 아닌 호출문을 할당해서 사용한다.
이벤트 핸들러 프로퍼티 방식에서는 DOM 노드의 이벤트 핸들러 프로퍼티에 함수 참조를 할당한다.
이벤트 핸들러를 등록할때 콜백함수와 마찬가지로 함수 참조를 등록해야 브라우저가 이벤트 핸들러를 호출할 수 있다.
만약 함수 참조가 아니라 함수 호출문을 등록하면 함수 호출문의 평가 결과가 이벤트 핸들러로 등록된다.
이때 평가가 함수가 아니라, 값이라면, 이는 호출되지 않는다.
예제에서 는 어트리뷰트 값으로 호출문을 할당했다. 이때 이벤트 핸들러 어트리뷰트 값은
암묵적으로 생성될 함수 몸체를 의미한다. onclick=“sayHi(‘lee’)”어트리뷰트는
Function onclick(event) {
sayHi(“lee”);
}
를 암묵적으로 할당된다.
위와 같은 방식을 바닐라 js와 같은 부분에서는 사용하지 않는것이 좋으나
CBD의 관점에서는 위와 같은 방식으로 이벤트를 처리한다.
40.3.2 이벤트 핸들러 프로퍼티 방식
window객체와 Document, HTMLElement 타입의
DOM 노드 객체는 이벤트에 대응하는 이벤트 핸들러 프로퍼티를
가지고 있다. 이벤트 핸들러 프로퍼티의 키는 이벤트 핸들러 어트리뷰트와 마찬가지로
onclick과 같이 on접두사와 이벤트 타입으로 이루어져 있다. 이벤트 핸들러 프로퍼티에 함수를
바인딩하면 핸들러가 등록된다.
이벤트 핸들러를 등록하기 위해 이벤트를 발생시킬 객체인 이벤트 타킷과 이벤트의 종류를
나타내는 문자열인 이벤트 타입, 그리고 이벤트 핸들러를 지정할 필요가 있다 .
이벤트 핸들러는 대부분 이벤트를 발생시킬 이벤트 타킷에 바인딩한다 하지만 타깃에
무조건 해야하는것은 아니고 캐치할 DOM 노드 객체에 바인딩하면 된다.
이벤트 핸들러 어트리뷰트 방식도 결국 DOM 노드 객체에 이벤트 핸들러 프로퍼티로 변환되어
사용되므로 결과적으로 이벤트 핸들러 프로퍼티 방식과 동일하다고 할 수 있음
이벤트 핸들러 프로퍼티 방식은 HTML 과 js가 뒤섞이는 문제를 해결할 수 있으나 하나의 이벤트 핸들러만
바인딩 할 수 있다는 단점이 존재한다.
40.3.3 addEventListener 메서드 방식
DOM level2 에서 도입된 EventTarget.prototype.addEventListener 메서드를 사용하여 이벤트 핸들러를
등록 할 수 있다. 앞서 살펴본 이벤트 핸들러 어트리뷰트 방식과, 이벤트 핸들러 프로퍼티 방식은 DOM level 0부터
제공되던 방식이다.
이방식은 하나의 이벤트에 여러개의 함수를 할당 할 수 있다는 장점이 있다.
같은 함수를 여러번 참조시킨다면 한번의 동작만 일어난다는 것을 알아 두어야 함.
40.4 이벤트 핸들러 제거
addEventListener 메서드로 등록한 이벤트 핸들러를 제거하려면 EventTarget.prototype.removeEventListener
메서드를 사용한다. removeEventListener메서드에 전달할 인수는 addEventListener메서드와 동일하다
이때 addEventListener메서드에 전달한 인수와 removeEventListener메서드에 전달한 인수가 일치하지 않으면
제거되지 않는다.
기명함수를 이벤트 핸들러로 등록할 수 없다면 호출된 함수, 즉 자기자신을 가르키는, arguments.callee를
이용해서 제거 할 수 있다.
하지만 이는 코드 최적화를 방해 하므로 strict mode 에서 사용이 금지된다.
40.5 이벤트 객체
생성된 이벤트 객체는 이벤트 핸들러의 첫 번째 인수로 전달한다.
이벤트 핸들러 어트리뷰트 방식의 경우 이벤트 객체를 전달받으려면 이벤트 핸들러의 첫 번째 매개변수 이름이 반드시 event여야 한다.
40.5.1 이벤트 객체의 상속 구조
위 그림의 Event, UIEvent, MouseEvent등 모두는 생성자 함수로 이를 호출하여 생성 가능하다.
이벤트 객체 중 일부는 사용자의 행위로 발생하고 일부는 자바스크립트 코드에 의해 인의적으로 발생한 것으로 이는 사용자가
정의하는 것이 아니라 내부적으로 알아서 처리된듯 하다.
40.5.2 이벤트 객체의 공통 프로퍼티
Event 인터페이스 즉 Event.prototype 에 정의되어 있는 이벤트 관련 프로퍼티의 경우 앞서 말했던 UIEvent, CustomEvent,
MouseEvent 와 같은 곳에 모두 상속된다.
공통 프로퍼티의 경우 MDN 과 같은 공간을 찾아보면서 사용하는것이 옳을듯 하다.
40.5.3 마우스 정보 취득
이 부분에서는 마우스 이벤트가 발생할 때 얻어보는 정보에 대해서 적혀있는데,
mouseleave, click, mouseenter 등 이런 이벤트가 발생했을때 얻을 수 있는 정보에 대해서 적혀있다.
하지만. 이부분들에 대해서는 이를 보는것이 아니라. 필요에 의해 찾아보는것이 옳은 방식이라고 생각된다.
간단하게 정리하면
마우스에 관련된 이벤트가 발생하면, 마우스 이벤트가 발생한다는것으로 정리 가능할 듯 하다.
40.5.4 키보드 정보 취득
마우스 정보 취득과 마찬가지의 내용으로 keydown, keyup , keypress, 와 같은 이벤트가
발생했을때 얻을 수 있는 정보에 대해서 서술되어 있다.
40.6 이벤트 전파
이번 장에서 제일중요한 부분이라고 생각이 되었다.
DOM 트리상에 존재하는 DOM 요소 노드에 발생한 이벤트가 DOM 트리를 통해 전파되고 이를
이벤트 전파 라고 한다.
여기서 이벤트는 이벤트를 발생 시킨 돔을 중심으로 트리를 통해 전파된다. 여기서
캡쳐링 단계, 타겟 단계, 버블링 단계 로 나뉘어 지는다. 여기서
윈도우에서 시작해서 이벤트 타깃 방향으로 전파되는것이 캡쳐링 단계
이후 이벤트 객체는 이벤트를 발생시킨 이벤트 타겟으로 전달되는것이 타깃단계
이후 이벤트 타겟에서 시작해서 다시 윈도우로 이동하는것이 버블링 단계 이다.
<!DOCTYPE HTML>
<html>
<body>
<div id="container">
<button>click</button>
</div>
<script>
const $container = document.querySelector("#container");
$container.addEventListener("click", e => {
console.log(`current Phase : ${e.eventPhase}`);
console.log(`event Target : ${e.target}`);
console.log(`current Target : ${e.currentTarget}`);
});
</script>
</body>
</html>
위와 같은 결과를 받을 수 있는데 이벤트가 최종 발생지는 Button이나, 현재 선택된 공간은 Div임을 알 수 있다는것이다.
위와 같은 방식을 통해 존재하지 않는 타겟에 대해서도 미리 이벤트를 주거나 하는 방식으로
코드를 작성할 수 있을듯 하다.
이벤트 핸들러 어트리뷰트 /프로퍼티 방식으로 등록한 이벤트 핸들러는 타깃 단계와 버블링 단계만 캐치할 수 있다.
하지만, addEventListener방식으로 등록한 이벤트 핸들러는 타깃 단계 뿐만아니라 캡쳐링 단계도 캐치 할 수 있다.
(3번째 인수로 true를 줘야만 가능)
이벤트를 발생시킨 이벤트 타깃은 물론 상위 DOM의 요소에서도 캐치 할 수 있다.
40.7 이벤트 위임
모든 네비게이션에 이벤트 핸들러에 각각의 event를 등록한다면 여러개의 이벤트를 등록해야 하지만
이의 상위에 이벤트를 등록하고 위의 내용을 이용하게 된다면, 하나의 이벤트만 등록해도 같은
일 을 할 수 있다는 내용이다 .
40.8 DOM 요소의 기본 동작 조작
40.8.1 DOM 요소의 기본 동작 중단
DOM 요소는 저마다 기본동작이 있다.
이때 기본동작을 저지하기 위해서 preventDefault()라는 것을 사용하여 해결한다.
40.8.2 이벤트 전파 방지
이벤트 객체의 stopPropagation 메서드는 이벤트 전파를 중지 시킨다.
이를 사용하게 되면 위에서 봤던 상위 요소가 캐치 할 수 없게 된다.
40.9 이벤트 핸들러 내부의 this
40.9.1 이벤트 핸들러 어트리뷰트 방식
핸들러 어트리뷰트의 값으로 지정한 문자열은 암묵적으로 생성되는 이벤트 핸들러 문이기 때문에
이벤트 핸들러에의해 일반 함수로 호출 할 수 있게 된다. 이때 일반 함수로 실행되게 되는
this의 경우 전역 객체를 가르키게 된다.
40.9.2 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식
이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리킨다.
40.10 이벤트 핸들러에 인수 전달
함수에 인수를 전달하려면 함수를 호출할 때 전달해야한다. 이벤트 핸들러 어트리뷰트 방식은 함수 호출문을
사용 할 수 있기 때문에 인수를 전달 할 수 있지만. 프로퍼티 방식과, addEventListener 메서드방식의 경우
이벤트 핸들러를 브라우저가 호출 하기 때문에 함수 자체를 등록해야한다.
40.11 커스텀 이벤트
40.11.1 커스텀 이벤트 생성
커스텀 이벤트 생성자 함수를 사용해서 새로운 타입으로 사용가능하다.
이는 preventDefault 메서드로 취소 할 수 없고 버블링 되지 않는다.
40.11.2 커스텀 이벤트 디스패치
생성된 커스텀 이벤트는 메서드로 디스패치 할 수 있다.
dispatchEvent 메서든 이벤트 핸들러를 동기처리 방식으로 호출한다.
on + 이벤트 타입 으로 이루어진 이벤트 핸들러 어트리뷰트/프로퍼티가 요소 노드에 존재하지 않기 때문이다.
onfoo 라는 이벤트 타입으로 커스텀 이벤트를 생성한 경우 이벤트 핸들러 어트리뷰트 /프로퍼티 방식으로는 핸들러를
등록 할 수 없다.