13장 자바스크립트 이벤트
1. 이벤트
- 문서나 브라우저에서 특정 순간에 일어 난 일
- DOM 레벨2에서 DOM 이벤트에 대한 표준화를 시작하였음
2. 이벤트 흐름
2.1 페이지에서 이벤트가 전달 되는 순서
- DOM 트리구조에서 각 요소(Element)에 이벤트를 부여할때 이벤트 흐름 방식을 지정 할 수 있다.
- 익스플로러는
버블링
, 넷스케이프는캡쳐링
방식을 지원한다.
2.2 버블링 방식
- 문서 트리에 가장 깊이 위치한 요소 부터 부모 페이지로 거슬러 올라가는 방식
- 마치 거품이 올라가는 모양 같아서 ‘버블링’ 이라고 이름 지어짐.
- 최신 브라우저는 모두 이벤트 버블링 방식을 지원을 한다.
- div 요소를 클릭하게 되면 아래의 그림과 같이 div 요소 부터 DOM 트리를 거슬러 올라간다.
2.3 캡쳐링 방식
- 최상위 노드에서 처음으로 이벤트가 발생하여 가장 명시적인 노드에서 마지막으로 발생한다.
- 이벤트가 의도한 요소에 도달하기 직전에 잡아채려는 목적으로 만들어졌다.
- IE 8이하에서는 지원을 하지 않기 때문에 많이 사용하지 않는다.
3.이벤트 핸들러 연결하는 방법
3.1 이벤트 핸들러(리스너) 란?
- 이벤트에 응답하여 호출되는 함수
3.2 HTML 이벤트 핸들러
- html 속성에 이벤트를 설정하는 방식
<input type="button" vlaue="click me!" onclick="alert(event.type);" />
3.3 html에 이벤트 핸들러를 할당하면 안좋은 이유!
- 핸들러 코드가 로드되기 이전에 html 요소를 통해 호출 할 수 있음.
- html 과 자바스크립트가 너무 단단히 묶이게 된다. (이벤트 핸들러 수정시 html과 script 모두 변경이 필요하다.)
4. DOM 레벨0 이벤트 핸들러
- 객체에 대한 참조를 얻는다.
- 이벤트 핸들러 프로퍼티에 핸들러 연결한다.
- 일반적으로 소문자로 입력한다.
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("clicked");
};
5. DOM 레벨0 핸들러 제거
btn.onclick = null;
6. DOM 레벨 2 이벤트 핸들러
- DOM 레벨0과의 차이점: 여러 개의 이벤트 핸들러를 연결 할 수 있다.
- 이벤트 추가: addEventListener()
- 캡처링: true
- 버블링: false
- 이벤트 제거: removeEventListner()
- 추가 등록시 동일한 함수 객체를 매개변수로 넘겨야 제거가 가능하다.
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert("clicked");
}, false);
7. 익스플로러 이벤트 핸들러
- 이벤트 등록: attachEvent()
- 이벤트 제거: detachEvent()
- IE8이하 버전은 버블링 방식만 지원한다.
8. DOM event 객체
- DOM과 관련된 이벤트가 발생하면 관련 정보는 모두
event
라는 객체에 저장된다. - 이 객체에는 이벤트가 발생한 요소, 이벤트 타입 같은 기본 정보는 물론 이벤트와 관련된 다른 데이터도 저장된다.
- 매개변수로
event
객체가 전달 된다. event
객체는 이벤트 핸들러가 아직 실행 중일 때만 존재하며 이벤트 핸들러가 실행을 마치면event
객체는 파과된다.
8.1 event 프로퍼티
- type: 발생한 이벤트 타입 (onclick, onload…)
- 포커스 이벤트: 요소가 포커스를 얻거나 잃을때 발생 (focus, blur, focusin, focusout)
- 마우스 이벤트: 마우스로 어떤 동작을 취할때 발생 (click, dbclick, mousedown …)
- 휠 이벤트: 마우스 휠로 어떤 동작을 취할때 발생 (mousewheel …)
- 키보드 이벤트: 키보드로 어떤 동작을 취할때 발생 (keydown, kypress, keyup, textInput …)
- 구성 이벤트: IME 를 통해 문자를 입력 할 때 발생
- 변경 이벤트: DOM 구조가 바뀔 때 발생(요소나 속성의 이름이 발생) (DOMNodeInserted,DOMNodeRemoved,DOMAttrModifed… )
- bubbles: 이벤트가 버블링 되는지 나타낸다.
- cancelable: 이벤트의 기본 동작을 처리 할 수 있는지 나타낸다.
- currentTarget: 현재 이벤트를 처리 중인 요소, 이벤트 핸들러의 내부의 this와 같다.
- target: 이벤트의 실제 타깃
8.2 event 함수
- preventDefault()
- 이벤트의 기본 동작을 취소한다.
- 이벤트를 취소하려면 해당 이벤트의
cancelable
프로퍼티가true
여야 한다.
<a href="#" id="myLink"> 링크 </a>
var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault();
};
- stopPropagation()
- 이벤트 전파를 막는다. (캡처링, 버블링을 모두 취소)
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
alert("Clicked");
event.stopPropagation();
};
document.body.onclick = function(event) {
alert("Body Clicked");
};
// Clicked
9. UI 이벤트
9.1 load 이벤트
- 이미지, 자바스크립트, CSS 같은 외부 자원을 포함해 전체 페이지를 완전히 불러왔을 때 호출됨
- window 객체에 load event에 handler를 할당 할 수 있다.
- <body> 요소에 onload 속성 추가할 수 있다.
- html에서는 window객체에 접근할 수 없기 때문에 일종의 핵 같은 방식
- <img> 요소에도 사용가능 (이미지을 불러 왔을 때 hanlder 호출)
9.2 unload 이벤트
- 다른 페이지로 이동할 때 발생된다.
- 참조를 제거하여 메모리 누수를 방지하는 목적으로 사용한다.
- 모든 것이 해제 될때 발생하므로 페이지에 존재하던 객체를 전부 사용 할 수 없다.
- DOM 노드의 위치나 외형을 조작하려 하면 에러가 발생 할 수 있다.
9.3 resize 이벤트
- 익스플로러/사파리/크롬/오페라: 사용자가 브라우저 창 크기를 조절하는 동안 계속 발생
- 파이어폭스: 창 크기 조절을 멈추는 시점에 발생
9.4 scroll 이벤트
- html 요소의 scrollTop과 scrollLeft 를 이용
- document.documentElement.scrollTop
- document.docuemntElement.scrollLeft
- 사파리의 경우 body 요소에 포함
- document.body.scrollTop
- document.body.scrollLeft
- 문서를 스크롤 하는 동안 반복 실행된다.
9.5 focus 이벤트
blur
: 포커스를 잃을때 발생 (버블링 지원X)focus
: 요소가 포커스를 받을 때 발생 (버블링 지원X)focusin
: 요소가 포커스를 받을 때 발생 (버블링 지원O)focusout
: 요소가 포커스를 잃을 때 발생 (버블링 지원O)- 부모가 div고 내부에 input 요소가 있을때
- input 요소에
focusin
이벤트 발생시 부모 div에도 그 이벤트가 전달된다. - input 요소에
focus
이벤트 발생시 부모 div에는 그 이벤트가 전달되지 않는다.
- input 요소에
10. 마우스 이벤트
10.1 이벤트 종류
click
: 사용자가 주요 마우스 버튼(일반적으로 왼쪽 버튼)을 클릭하거나 엔터키를 누를 때 발생dbclick
: 사용자가 주요 마우스 버튼을 더블 클릭할 때 발생mousedown
: 사용자가 마우스 버튼을 누를 때 발생mouseenter
: 마우스 커서가 요소 밖에서 요소 경계 안으로 처음 이동할 때 발생DOM 레벨3
버블링X
mouseleave
: 마우스 커서가 요소 위에 있다가 경계 밖으로 이동 할 때 발생DOM 레벨3
버블링X
mousemove
: 마우스 커서가 요소 주변을 이동하는 동안 계속 발생mouseout
: 마우스 커서가 요소 위에 있다가 다른 요소 위로 이동할 대 발생mouseover
: 마우스 커서가 요소 바깥에 있다가 요소 경계 안으로 이동할 때 발생mouseup
: 사용자가 마우스 버튼을 누르고 있다가 놓을 때 발생
10.2 마우스 이벤트 발생 순서
mousedown
mouseup
click
mousedown
mouseup
click
dbclick
11 좌표
11.1 클라이언트좌표
- 클라이언트 영역 내에서의 좌표
- 스크롤은 계산하지 않는다.
- event.clientX
- event.clientY
11.2 페이지좌표
- 페이지 기준의 좌표
- event.pageX
- event.pageY
- 스크롤 계산포함
11.3 화면좌표
- 전체 화면 기준의 좌표
- 브라우저를 움직여도 값이 같음.
- event.screenX
- event.screenY
$(document).click(function(event){
console.log("clientX : " + event.clientX + "\nclientY : " + event.clientY);
console.log("pageX : " + event.pageX + "\npageY : " + event.pageY);
console.log("screenX : " + event.screenX + "\nscreenY : " + event.screenY);
});
12 마우스 휠 이벤트
- onmousewheel 이벤트 핸들러
- event.wheelDelta : 마우스 휠을 어떤 방향으로 얼마만큼 움직였는지에 대한 정보
13 키보드 이벤트
keydown
: 사용자가 키를 처음 누를 때 발생하며 누르고 있는 동안 계속 발생keypress
: 사용자가 키를 누른 결과로 문자가 입력되었을 때 처음 발생하며 누르고 있는 동안 계속 발생- esc 키에서도 발생
- DOM 레벨 3 에서는 폐기되었으므로 textInput 이벤트를 권장
keyup
: 사용자가 키에 손을 뗄 때 발생
13.1 사용자가 키를 누르면 아래와 같은 순서로 이벤트가 발생
- keydown
- keypress (텍스트 입력 전 발생)
- keyup (텍스트 입력이 된 후에 발생)
13.2 키 코드
- keydown 과 keyup 이벤트에서 event 객체의 keyCode 프로퍼티에는 각 키에 대응하는 코드가 있다.
- keyCode 는 아스키 값이 들어간다.
- 예를들어 7은 55, a나 A는 65 이다.(shift 키 상태와 관계없이)
- DOM 레벨3에서는
key
와char
두 가지 프로퍼티가 추가 되었다.key
프로퍼티의 값은 문자 키 인 경우 그대로의 문자 값 (a, A)- 문자가 아닌 키 인 경우 키 이름(shift, down)
char
프로퍼티의 값은 문자 인경우key
프로퍼티와 동일하고, 문자가 아닌 값은null
이 들어간다.
14 텍스트 이벤트
14.1 textInput 이벤트
- DOM 레벨3 에서는 편집 가능한 영역에 문자가 입력 될 때 발생하는 textInput 이벤트를 추가하였다.
- keypress를 교체할 목적으로 만들어짐
- keypress 이벤트와의 차이점
- keypress 이벤트는 포커스를 받을 수 있는 요소 전체에 대해 지원
- 즉, 백스페이스나 esc 키 같은 키는 무시
- textInput은 키를 누른 결과로 새문자가 삽입될 키에 대해서만 동작
- keypress 이벤트는 포커스를 받을 수 있는 요소 전체에 대해 지원
- event 객체의 data 프로퍼티에 삽입된 문자 자체가 저장됨
- shift와 a를 누르면 event.data = A, a만 누르면 event.data= a
15 조작 이벤트
-
DOM 레벨2 에서는 DOM의 일부가 변경되었을 때 알리는 이벤트를 제공한다.
DOMSubtreeModified
: DOM 구조가 어떻게든 변경되었을 때 발생DOMNodeInserted
: 노드가 다른 노드의 자식으로 삽입될 때 발생DOMNodeRemoved
: 노드가 부모 노드로부터 제거될 때 발생DOMNodeInsertedIntoDocument
: 노드가 직접적으로 또는 자신이 존재하는 서브트리를 통해 삽입되었을 때 발생 (DOM 레벨3에서 폐기)DOMNodeRemovedFromDocument
: 노드가 직접적으로 또는 자신이 존재하는 서브트리를 통해 제거되었을 때 발생 (DOM 레벨3에서 폐기)DOMAttrModifed
: 속성이 바뀌었을 때 발생 (DOM 레벨3에서 폐기)DOMCharacterDataModifed
: 텍스트 노드의 값이 변경될 때 발생
15.1 노드 제거
- removeChild()나 replaceChild()로 DOM에서 노드를 제거한다.
- DOMNodeRemoved 이벤트가 발생한다.
event.target
프로퍼티에는 제거된 노드의 참조가 있다.event.relatedNode
프로퍼티에는 부모 노드에 대한 참조가 있다.- 이 이벤트가 발생하는 시점에서는 아직 노드가 제거 된 상태가 아니다.
- 즉, element의 parentNode 프로퍼티는 event.relatedNode와 같다.
15.2 노드 삽입
- appendChild()나 replaceChild(), insertBefore()로 노드를 DOM에 삽입한다.
- DOMNodeInserted 이벤트가 발생한다.
event.target
프로퍼티에는 삽입된 노드의 참조가 있다.event.relatedNode
프로퍼티에는 부모 노드에 대한 참조가 있다.
16. html5 event
16.1 beforeunload
- 페이지를 언로드 하기 직전에 발생
- 확인메시지를 통하여 페이지에 계속 머무를지 닫을지 확인한다.
document.body.addEventListener("beforeunload",function(event){
var message = "이 페이지에서 정말로 나가겠습니까?";
// 대화 상자에 표시할 문자열을 지정한다.
event.returnValue = message;
// 사파리와 크롬에서는 함수 값으로 반환이 필요
return message;
},false);
16.2 DOMContentLoaded
- DOM 트리가 완전히 구성되면 발생
- 외부자원(이미지, 자바스크립트, CSS 등)는 기다리지 않는다.
- 이벤트 핸들러 등록, DOM 조작에 사용
17 메모리와 성능
17.1 이벤트 핸들러와 성능의 관계
- 이벤트 핸들러의 개수가 성능에 직접적으로 영향을 미친다.
- 각 함수가 메모리를 점유하는 객체 이기 때문이다. 메모리에 객체가 많을 수록 성능은 떨어진다.
- 이벤트 핸들러를 많이 할당 할 수록 DOM 접근이 많아진다.
17.2 이벤트 핸들러의 성능 최적화
- 이벤트 버블링의 장점을 활용하여 이벤트 핸들러를 하나만 할당하여 이벤트를 처리하는 방식을 사용한다.
<ul id="myLinks">
<li id="item1"> itme1 </li>
<li id="item2"> itme2</li>
<li id="item3"> itme3 </li>
</ul>
var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch(target.id){
case "item1":
document.title = "I changed the document's title";
break;
case "item2":
location.href = "http://www.wrox.com";
break;
case "item3":
console.log("hi");
break;
}
});
17.3 이벤트 핸들러 제거
- 페이지를 떠나기 전 제거하지 않은 이벤트 핸들러는 메모리에 계속 남는다.
- onunload 이벤트 핸들러를 써서 이벤트 핸들러를 모두 제거한다.