[노란책] 13. 이벤트 (작성중)
13. 이벤트
이벤트 흐름
- 이벤트 캡처링: DOM 트리 상위 -> 하위, 이벤트 캡처용 외에는 사용하지 말아야 함(오래된 브라우저에서는 캡처링을 지원하지 않음)
- 이벤트 버블링: DOM 트리 하우 -> 상위, 일반적인 브라우저 이벤트
- 이벤트 흐름: 이벤트 캡처링 - (타깃: 버블링에 포함) - 버블링
이벤트 핸들러
마크업에 엘리먼트 프로퍼티로 적용하기
<input id="nameInput" onchange="console.log(this.value)" />
- 마크업으로 자바스크립트 코드를 값으로 넣는다.
- this 값은 엘리먼트이다.
- 스코프가 확장되어 document, 해당 event 객체 등에 접근할 수 있다.
- 신기하게도 폼 엘리먼트 하위 엘리먼트의 이벤트 핸들러인 경우, form 엘리먼트까지 스코프가 확장되어 형제 엘리먼트에 접근할 수 있다.
- 마크업과 Javascript가 너무 강하게 결합되는 단점이 있다.
- 그래서 주로 자바스크립트 단에서 엘리먼트의 프로퍼티로 이벤트 핸들러를 추가하는 방식을 선호한다.
크로스 브라우징 이벤트 핸들러
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventHandler) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventHandler) {
element.removeEventHandler(type, handler, false); // addEventListener 설정할 때와 같은 함수 레퍼런스를 전달해주어야 함
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler); // attachEvent 설정할 때와 같은 함수 레퍼런스를 전달해주어야 함
} else {
element["on" + type] = null
}
}
}
- 우선순위: DOM 레벨2 > IE fallback > DOM 레벨0
DOM 레벨2 | IE8 이하 fallback | DOM 레벨 0 |
---|---|---|
2개 이상 이벤트를 추가할 수 있다 | 2개 이상 이벤트를 추가할 수 있다 | 1개만 추가할 수 있다 |
추가한 순서대로 실행된다 | 추가한 순서의 반대대로 실행된다 | . |
this는 엘리먼트 | this는 window | this는 엘리먼트 |
버블링(기본), 캡처링 | 버블링 | 버블링 |
이벤트 객체
DOM 이벤트 객체 | IE 이벤트 객체 |
---|---|
type | type |
이벤트 핸들러의 매개변수로 전달 | window 객체의 프로퍼티* |
target | srcElement |
stopPropagation() | cancelBubble = true |
preventDefault() | returnValue = false |
*
: attachEvent로 등록한 경우 편의를 위해 매개변수로 전달됨, DOM 레벨0으로 전달한 경우 매개변수로 전달되지 않으면 window 객체의 event 값을 참조하면 됨
메모리와 성능
- 이벤트 핸들러가 많은 수록 브라우저의 성능이 떨어진다.
- 이벤트 핸들러는 함수 형태로 메모리에 존재하는 객체이다. 제때 수거되어야 한다.
- DOM 접근이 많아져서 전체 페이지에 대한 응답성이 떨어진다.
- 이벤트 위임과 이벤트 핸들러를 (제때) 해제하는 방법으로 이벤트 핸들러로 인한 성능 저하를 막을 수 있다.
이벤트 위임
- 가장 상위 엘리먼트에서 여러 이벤트를 처리하는 방식
- 이벤트 핸들러를 설정, 관리 비용이 줄어든다.
- 페이지의 메모리 요구량이 준다.
- 가능하다면 document에 이벤트를 위임하는 것을 이 책에서는 추천함
- document 객체는 즉시 사용가능하다(load 이벤트를 기다릴 필요가 없음)
이벤트 핸들러 제거
- 엘리먼트가 DOM에서 제거되어도, 이벤트 핸들러가 제거되지 않는다면 계속 참조 가능하게 되므로 메모리에서 수거되지 않는다.
- 이런 실수가 발생하기 쉬운 지점은
- 이벤트 핸들러 내에서 innerHTML로 해당 엘리먼트는 사라지는 경우: DOM에서는 제거되지만, 여전히 이벤트 핸들러는 남아있다.
- 엘리먼트 제거 전 이벤트핸들러를 제거한다.
- 페이지를 나가는 경우
- unload 전 이벤트 핸들러를 제거한다.
- 이벤트 핸들러 내에서 innerHTML로 해당 엘리먼트는 사라지는 경우: DOM에서는 제거되지만, 여전히 이벤트 핸들러는 남아있다.
- DOM에서 해당 엘리먼트가 삭제된 경우, 이벤트 핸들러로 삭제해야 메모리에서 핸들러, 엘리먼트도 삭제된다. -> 성능 저하 이슈 피할 수 있음!