'나홀로스터디/JS For Web Dev'에 해당되는 글 14건

20장 JSON

2015. 3. 24. 13:57 나홀로스터디/JS For Web Dev


20장 JSON

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
- JSON 문법의 이해
- JSON 파싱
- JSON 직렬화 2.4 자바스크립트가 비활성화된 상황에 대한 대비

JSON은 자바스트립트의 엄격한 부분집합이며 자바스크립트의 여러 가지 패턴을 사용해 구조화된 데이터를 표현한다. XML대신 JSON을 권하는 이유는 eval()에 직접 넘길 수 있고 DOM을 따로 생성할 필요가 없기 때문이다.  JSON이 자바스크립트와 문법을 공유하긴 하지만 가장 중요한 점은 JSON이 프로그래밍 언어가 아니라 데이터 형식임을 이해하는 것이다. 많은 프로그래밍 언어에서 JSON 파싱과 직렬화를 지원한다.



20.1 문법

JSON 문법은 세가지 타입을 사용한다.JSON은 구조회된 데이터를 표현하는 방식일 뿐이며 자바스크립트의 문법과 매우 비슷하다.

 - 단순한값 : 문자열, 숫자, 불리언, null은 모두 자바스크립트와 같은 문법으로 표현한다. undefined는 지원되지 않는다. 

- 객체 : 객체는 순서 있는 키-값 쌍으로 표현된다. 각 값은 원시 타입일수도 있고 객체나 배열같은 복잡한 타입일수도 있다.

- 배열 : 배열은 숫자형 색인으로 접근할 수 있는 순서 있는 목록으로 표현한다. 각 값은 단순한 값이나 객체, 다른 배열 등을 모두 쓸 수 있다.



20.1.1 단순한 값

자바스크립트 문자열과 JSON 문자열의 차이는 JSON 문자열은 반드시 큰 따옴표로 감싸야만 유효하다는 점이다. 불리언 값과 null은 그 자체로 유효한 JSON이나 현실적으로 JSON은 복잡한 구조를 표현하기 위해 사용한다. 



20.1.2 객체

JSON 객체는 객체 리터럴 표기법과 매우 비슷하지만 자바스크립트 예제와는 몇가지 다른 점이 있다. 첫번째, 변수 선언이 없다. 두번째, 문장을 마치는 세미콜론이 없다. 자바스크립트 문장이 아니므로 필요없다. 값은 JSON에서 허용하는 모든 타입을 쓸 수 있으며 객체 안에 객체를 써도 된다. 


{
  "name" : "Nicholas",
  "age" : 29,
  "school": {
    "name" : "Merrimark College"
  }

20.1.3 배열

JSON 배열은 자바스크립트의 배열 리터럴 표기법으로 표현하는데 변수와 세미콜론은 없다. 



20.2 파싱과 직렬화

JSON은 친근한 문법 뿐만 아니라 데이터를 파싱하면 바로 사용할 수 있는 자바스크립트 객체가 된다. 



20.2.1 JSON 객체

JSON 객체에는 stringify()parse() 두가지 메서드가 있는데 이들 메서드는 각각 자바스크립트 객체를 JSON 문자열로 직렬화하며 JSON을 파싱하여 네이티브 자바스크립트 값으로 바꾼다. 

JSON.stringify()는 자바스크립트 객체를 JSON 문자열로 직렬화하고, JSON 문자열을 JSON.parse()에 넘기면 적절한 자바스크립트 값이 생성된다. 자바스크립트 객체를 직렬화할 때는 모든 함수와 프로토타입 멤버가 생략되고 값이  undefined인 프로퍼티도 모두 생략한다. 



20.2.2 직렬화 옵션

JSON.stringify() 메서드는 직렬화할 객체 외에 두 가지 매개변수를 더 받을 수 있는데 이들 매개변수는 자바스크립트 객체를 직렬화할 때 적용할 옵션을 설정한다. 첫 번째 매개변수는 필터이며 배열이나 함수를 쓸 수 있다. 두 번재 매개변수는 JSON 문자열의 들여쓰기를 조절한다. JSON.stringify()가 제공하는 기능 이상이 필요할때 toJSON() 메서드를 사용할수 있는데 toJSON() 메서드는 어떤 직렬화 값도 반환하게 할 수 있으며 적절히 동작한다. toJSON() 메서드를 필터 함수와 함께 쓸 수도 있으므로 다양한 직렬화 과정이 어떤 순서로 발생하는지 이해하는 것이 중요하다. 


- toJSON() 메서드가 있으면 호출하여 그 값을 사용하고 그렇지 않다면 기본 직렬화 방법을 사용한다. 

- 두번째 매개변수가 있다면 필터를 적용한다. 필터 함수에 전달되는 값은 1단계에서 반환된 값이다.

- 2단계에서 반환한 각 값을 적절히 직렬화하낟.

- 세번째 매개변수가 있으면 그에 따라 형식을 적절히 조절한다. 



20.2.3 파싱 옵션

JSON.parse() 메서드 역시 각 키-값 쌍에서 호출될 콜백 함수를 추가적인 매개변수로 받는다. 



'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

14장 폼스크립트  (0) 2015.03.18
이벤트  (0) 2015.01.07
DOM 확장  (0) 2014.12.18
DOM  (0) 2014.12.08
클라이언트 감지  (0) 2014.11.20

14장 폼스크립트

2015. 3. 18. 11:36 나홀로스터디/JS For Web Dev


14장 폼스크립트

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
- 폼의 기본에 관한 이해
- 텍스트 박스 유효성 검사와 상호작용
- 다른 폼 컨트롤 사용


자바스크립트의 원래 목적 중 하나는 폼 처리를 브라우저에서 분담하여 서버까지 왕복하는 일을 줄이는 것이었는데 웹 폼에서 일반적인 문제에 대한 네이티브 솔루션을 제공하지 못하자 개발자들은 자바스크립트로 필드의 유효성을 검사하고 표준 폼 컨트롤의 기본 동작을 확장하기 시작했다. 



14.1 폼 기본

웹 폼은 HTML에서는 <form> 요소로, 자바스크립트에서는 HTMLFormElement 타입으로 표현된다. HTMLFormElement에서는 HTMLElement를 상속하므로 다른 HTML 요소와 같은 프로퍼티를 가진다. HTMLFormElement에는 다음 프로퍼티와 메서드가 추가된다.


- acceptCharset - 서버가 처리할 수 있는 문자셋, HTML의 accept-charset 속성과 같다.

- action - 요청을 보낼 URL, HTML의 action 속성과 같다.

- elements - 폼에 있는 컨트롤 전체의 HTMLCollection이다.

- enctype - 요청의 인코딩 타입, HTML의 enctype 속성과 같다.

- length- 폼에 있는 컨트롤 개수이다.

- method - HTTP 요청 타입이며 일반적으로 "get"이나 "post"이다. HTML의 method 속성과 같다.

- name - 폼의 이름, HTML의 name 속성과 같다.

- reset() - 품 필드를 모두 기본 값으로 리셋한다.

- submit() - 폼을 전송한다.

- target - 요청을 보내고 응답을 받을 창 이름이다. HTML의 target 속성과 같다.


<form> 요소에 대한 참조를 얻는 데 가장 많이 쓰이는 방법은 id속성을 지정한 후 getElemenetById()를 이용하는 것이다. 

var form = document.getElementById("form1");

폼은 document.forms 컬렉션을 통해서 숫자형 인덱스name으로도 접근할 수 있다.

var firstForm = document.forms[0];   // 페이지의 첫 번째 폼
var myForm = document.forms["form2"];   // 이름이 "form2"인 폼

폼에는 id와 name을 모두 쓸 수 있고 두 값이 같을 필요는 없다. 


14.1.1 폼 전송

전송 버튼은 <input>요소나 <button> 요소의 type 속성을 "submit"으로 지정해서 정의하고 이미지 버튼은 <input> 요소의 type 속성을 "image"로 지정해서 정의한다. 

<input type="submit" value="Submit Form">  // 범용 전송 버튼
<button type="submit">Submit Form</button>  // 커스텀 전송 버튼
<input type="image" src="graphic.gif">  // 이미지 버튼
이들 버튼 타입이 폼에 들어있으면 폼 컨트롤에 포커스가 있는 상태에서 엔터 키를 눌러도 폼이 전송된다.



14.1.2 폼 리셋

리셋 버튼은 <input>이나 <button>요소의 type 속성을 "reset"으로 지정하여 생성한다.

<input type="reset" value="Reset Form"> // 범용 리셋 버튼
<button type="reset">Reset Form</buttom>  // 커스텀 리셋 버튼


14.1.3 폼 필드

폼 요소도 네이티브 DOM 메서드로 접근할 수 있는데 폼 요소는 각 폼의 프로퍼티인 elements 컬렉션에 속한다.  elements 컬렉션은 폼에 포함된 모든 폼 필드에 대한 참조의 순서 있는 목록이며 <input>, <textarea>, <button>, <selet>, <fieldset> 요소가 이 컬렉션에 속하고, 인덱스와 name 두 가지로 접근 가능하다. 



공통 폼 필드 메서드

각 폼필드에 공통인 메서드는 focus()와 blue()이다. focus() 코드는 요소의 type속성이 hidden이거나 display 또는 visibility로 숨긴 필드일 경우 에러가 발생하므로 HTML5에서는 폼 필드에 autofocus 속성을 도입하여 이를 지원하는 브라우저에서는 자바스크립트를 쓰지 않아도 자동으로 요소에 포커스를 옮긴다. focus()의 반대로 요소에서 포커스를 제거하는 메서드는 blur()이다. 



폼 필드 공통 이벤트

- blur : 필드가 포커스를 잃을 때 발생

- change : 필드가 포커스를 잃고 <input>이나 <textarea> 요소에서는 value가 바뀔 때 <select> 요소에서는 선택된 옵션이 바뀔때 발생

- focus : 필드가 포커스를 받을 때 발생




14.2 텍스트 박스 스크립트

HTML에는 한 줄짜리 텍스트 박스인 <input> 요소와 여러 줄 텍스트 박스인 <textarea> 요소가 있다. value 속성은 텍스트 박스의 초기 값이며 maxlength 속성은 텍스트 박스에 최대 몇 글자까지 입력할 수 있는지 나타낸다.  두 텍스트 박스는 모두 콘텐츠를 value 프로퍼티에 저장한다. 따라서 다음과 같이 value 프로퍼티의 값을 통해 텍스트 박스의 값을 읽고 쓸수 있다. 



14.3 <select> 요소 스크립트

SELECT 박스는 <select> 요소와 <option> 요소로 생성한다. 

- 선택된 옵션이 없으면 SELECT 박스의 값은 빈 문자열이다.

- 선택된 옵션이 있고 해당 옵션에 value 속성이 있다면 SELECT 박스의 값은 선택된 옵션의 value 속성이다. value 속성이 빈 문자열이어도 그대로 적용된다. 

- 선택된 옵션에 value 속성이 없으면 SELECT 박스의 값은 해당 옵션의 텍스트이다. 

- 여러 옵션이 선택되었으면 SELECT 박스의 값은 선택된 첫 번째 옵션을 따르며 이전 규칙을 적용한다. 



14.4 폼 직렬화

Ajax가 등장하면서 '폼직렬화'가 주요 과제가 되었다.  자바스크립트로 폼을 직렬화 할때는 type, name, value 프로퍼티를 함께 사용한다.

- 필드 이름과 값을 URL 인코드하고 앰퍼샌드로 구분한다.

- 비활성 필드는 전송하지 않는다. 

- 체크 박스와 라디오 버튼은 체크된 것만 전송한다. 

- type이 "reset"이나 "button"으로 지정된 버튼은 전송하지 않는다.

- 다중 선택 필드는 선택된 항목을 모두 전송한다.

- 폼을 전송할 떄 전송 버튼을 클릭했다면 해당 버튼을 전송하며 그렇지 않다면 전송 버튼은 보내지 않는다. type이 "image"로 지정된 <input> 요소는 전송 버튼과 같이 취급한다. 

- <select> 요소의 값은 선택된 <option> 요소의 value 속성이다. <option> 요소에 value 속성이 없다면 해당 요소의 텍스트를 값으로 사용한다. 


serialize() 함수는 문자열을 쿼리스트링 형식으로 반환하지만 다른 직렬화 형식으로 쉽게 바꿀수 있다.



14.5 리치 텍스트 편집

웹 애플리케이션에서 가장 흔히 필요한 기능은 웹 페이지의 리치 텍스트를 편집하는 기능('위지웍WYSIWYG')으로 기본 테크닉은 페이지에 빈 HTML 파일을 포함한 iframe 을 삽입하는 것이다. 편집하려면 반드시 designMode를 "on"으로 설정해야 하며 문서를 완전히 불러온 후에만 가능하다. 





'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

20장 JSON  (0) 2015.03.24
이벤트  (0) 2015.01.07
DOM 확장  (0) 2014.12.18
DOM  (0) 2014.12.08
클라이언트 감지  (0) 2014.11.20

이벤트

2015. 1. 7. 17:56 나홀로스터디/JS For Web Dev

 

13장 이벤트

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
- 이벤트 흐름에 대한 이해
- 이벤트 핸들러 다루기
- 여러 가지 타입의 이벤트


자바스크립트와 HTML 의 상호작용은 문서나 브라우저 창에서 특정 순간에 일어난 일을 가리키는 '이벤트'에 의해 처리된다. 이벤트는 '리스너'(핸들러라고 부르기도 한다)로 추적하며 리스너는 이벤트가 일어날 때만 실행된다. 전통적인 소프트웨어 공학에서는 이 모델을 옵저버 패턴이라 부르고 이 패턴은 자바스크립트에서 정의하는 페이지 행동과 HTML 및 CSS에서 정의하는 페이지 외형 사이에 '느슨한'  연결을 형성한다.
주요 브라우저가 DOM 레벨2 이벤트를 구현하긴 했지만 명세도 이벤트 타입을 전부 다루지는 못했다.

 

 


13.1 이벤트 흐름
'이벤트 흐름'은 페이지에서 이벤트가 전달되는 순서를 설명하는데 흥미롭게도 인터넷 익스플로러와 넷스케이프 개발팀은 이벤트 흐름에서 서로 정반대 순서를 채택했다. 인터넷 익스플로러는 이벤트 버블링을 지원했고 넷스케이프 커뮤니케이터는 이벤트 캡처링을 지원했다.


13.1.1 이벤트 버블링
인터넷 익스플로러의 이벤트 흐름은 '이벤트 버블링'이라 부르는데 이벤트가 가장 명시적인 요소, 즉 이벤트 흐름상 문서 트리에서 가장 깊이 위치한 요소에서 시작해 거슬러 흐르는 모양이 마치 거품이 올라가는 것 같았기 때문이다.  페이지에서 <div> 요소를 클릭하면 click 이벤트가 <div>, <body>, <html>, document 순으로 발생한다.  최신 브라우저는 모두 이벤트 버블링을 지원하지만 인터넷 익스플로러 5.5 및 이전버전에서는 <html> 요소를 건너뛰고 <body> 요소에서 document로 바로 올라갔다. 인터넷 익스플로러 9와 파이어폭스, 크롬, 사파리에서는 이벤트가 window 객체까지 올라간다.


13.1.2 이벤트 캡처링
넷스케이프 커뮤니케이터 팀은 이벤트 캡처링이란 이벤트 흐름을 만들었는데 이것은 최상위 노드에서 처음으로 이벤트가 발생하여 가장 명시적인 노드에서 마지막으로 발생한다. 이벤트 캡처링은  원래 넷스케이프 커뮤니케이터에서만 사용했지만 현재는 인터넷 익스플로러9, 사파리, 크롬, 오페라, 파이어폭스에서 지원한다. 오래된  브라우저에서는 이벤트 캡처링을 지원하지 않으므로 이벤트 버블링을 주로 쓰고 이벤트 캡처링은 특별한 상황에서만 쓰길 권한다.


13.1.3 DOM 이벤트 흐름
DOM 레벨2 이벤트에서 정의한 이벤트 흐름에는 이벤트 캡처링 단계, 타깃 단계, 이벤트 버블링 단계 세 가지가 있다. 이벤트 캡처링이 처음 발생하므로 필요하다면 이 단계에서 이벤트를 가로챈다. 다음에는 실제 타깃이 이벤트를 받는다. 마지막으로 이벤트 버블링이 발생하며 이벤트에 반응할 수 있는 마지막 기회다. 

※ 인터넷 익스플로러 9와 오페라, 파이어폭스, 크롬, 사파리는 모두 DOM 이벤트 모델을 지원하며 인터넷 익스플로러8 및 이전 버전에서는 지원하지 않는다.

 

 

 

 

13.2 이벤트 핸들러
이벤트란 사용자 또는 브라우저가 취하는 특정 동작이다. 이벤트에는 click이나 load, mouseover 같은 이름이 있다. 이벤트에 응답하여 호출되는 함수를 '이벤트 핸들러'('이벤트 리스너')라고 부른다. 이벤트 핸들러 이름은 'on'으로 시작한다.


13.2.1 HTML 이벤트 핸들러
각 요소가 지원하는 이벤트는 이벤트 핸들러 이름을 HTML 속성에 사용하여 할당할 수 있다. 속성 값은 실행할 자바스크립트 코어여야 한다.

<input type="button" value="Click Me" onclick="alert('Clicked')" />

 

자바스크립트 코드도 속성 값이므로 앰퍼센트(&)나 큰 따옴표, <,> 같은 HTML문법 문자를 이스케이프 없이 쓸수는 없다.
이벤트 핸들러는 외부 파일에 정의할수도 있고 실행하는 코드는 전역 스코프에서 실행된다. 이런 방식으로 할당한 이벤트 핸들러에는 몇 가지 특성이 있다. 먼저 attribute 값을 감싸는 함수가 생성된다. 이 함수에는 event 라는 특별한 로컬 변수가 있고 이 변수는 이벤트 객체다. 함수 내부에서 this값은 이벤트 타깃 요소와 일치한다. 

<input type="button" value="Click Me" onclick="alert(event.type)" />
<input type="button" value="Click Me" onclick="alert(thistype)" />

동적으로 생성되는 함수에서 스코프 체인이 확장되는데 함수 내부에서는 document와 해당 요소의 멤버에 마치 로컬 변수처럼 접근할 수 있다. 이 스코프 체인 확장은 with를 통해 이루어진다.  

function(){
  with(document){
    with(this){
    // 속성 값
    }
  }
}

HTML에 이벤트 핸들러를 할당하는 방법에는 몇가지 단점이 있다.
첫번째는 타이밍의 문제다. 이벤트 핸들러 코드가 준비되기 전에 HTML 요소가 화면에 나타나고 사용자가 이를 조작할 가능성이 있다.
두번째는 식별자 해석에 사용하는 규칙이 자바스크립트 엔진에 따라 미묘하게 달라 이벤트 핸들러 함수의 스코프 체인 확장 결과가 브라우저마다 다르다는 것이다.
마지막 단점은 이벤트 핸들러를 HTML에서 할당하면 HTML과 자바스크립트가 너무 단단히 묶여 이벤트 핸들러를 바꿀때 HTML과 자바스크립트 코드를 모두 바꿔야 할 수도 있다.


13.2.2 DOM 레벨0 이벤트 핸들러
자바스크립트에서 이벤트 핸들러를 할당하는 전통적인 방법은 이벤트 핸들러 프로퍼티에 함수를 할당하는 방법이다. 자바스크립트에서 이벤트 핸들러를 할당하려면 우선 객체에 대한 참조를 얻어야 한다. window와 document를 포함해 모든 요소에는 이벤트 핸들러 프로퍼티가 있으며 onclick처럼 일반적으로 소문자이다. 이 프로퍼티를 다음과 같이 함수로 설정하면 이벤트 핸들러가 할당된다.  

var btn = document.getElementById("myBtn");
btn.onclick = function(){
  alert(this.id);
}

이런 방식으로 추가한 이벤트 핸들러는 이벤트 흐름에서 버블링 단계에 실행되도록 의도한 것이다. DOM 레벨 0 접근법으로 할당한 이벤트 핸들러를 제거할 때는 해당 이벤트 핸들러 프로퍼티를 null로 설정한다.

※ 이벤트 핸들러를 HTML에서 할당하면 onclick 프로퍼티의 값은 HTML 속성에서 설정한 코드가 담긴 함수이다. 따라서 요소의 이벤트 핸들러 프로퍼티를 null로 설정하면 HTML에서 할당한 이벤트 핸들러도 제거된다.

 


13.2.3 DOM 레벨 2 이벤트 핸들러
DOM 레벨 2 이벤트에서는 이벤트 핸들러 할당과 제거를 담당하는 메서드로 addEventListener()removeEventListener()를 정의했다. 이 메서드는 모든 DOM 노드에 존재하며 매개변수로 이벤트 이름, 이벤트 핸들러 함수, 이벤트 핸들러 캡쳐 단계에서 호출할지(true), 버블링 단계에서 호출할지(false) 나타내는 불리언 값 세 가지를 받는다.

btn.addEventListener("click", function(){
  alert(this.id);
}, false);

DOM 레벨 2 메서드의 주요 장점은 이벤트 핸들러를 '추가'하므로 이벤트 핸들러가 여러 개 있을 수 있다는 점이다.  addEventListener()로 추가한 이벤트 핸들러는 핸들러를 추가할 때와 같은 매개변수를 넘기면서 removeEventListener()를 호출해야 제거할 수 있다.

※ DOM 레벨 2 이벤트 핸들러를 지원하는 브라우저는 인터넷 익스플로러 9, 파이어폭스, 사파리, 크롬, 오페라이다.

 

 

13.2.4 인터넷 익스플로러 이벤트 핸들러
인터넷 익스플로러는 DOM 표준과 비슷한 attachEvent(), detachEvent() 두 메서드를 구현했다. 두 메서드는 핸들러 이름이벤트 핸들러 함수 두 가지를 매개변수로 받는다. 인터넷 익스플로러 8 및 이전 버전은 이벤트 버블링만 지원하므로 attachEvent()로 추가한 이벤트 핸들러는 버블링 단계에서만 실행된다.  

btn.attachEvent("onclick", function(){
  alert("Clicked");
})

DOM 레벨 0 접근법에서 이벤트 핸들러의 this는 요소이지만 attachEvent()로 등록한 이벤트 핸들러는 전역 컨텍스트에서 실행되므로 this는 window이다. attachEvent()도 두번 호출해서 두가지 이벤트 핸들러를 추가할 수 있는데 추가한 순서와 반대의 순서로 실행된다. attachEvent()로 추가한 이벤트 핸들러를 제거할 때는 detachEvent()에 같은 매개변수를 넘겨 호출한다.

※ 인터넷 익스플로러 스타일의 이벤트 핸들러는 인터넷 익스플로러와 오페라에서 지원한다.

 


13.2.5 크로스 브라우저 이벤트 핸들러
많은 개발자들이 브라우저 이벤트 처리 차이를 메우기 위해 자바스크립트 라이브러리를 쓰거나 커스텀 코드를 작성하는데 이벤트 처리 코드가 가능한 한 많은 브라우저에서 동작하게 하려면 버블링 단계에서만 동작하도록 해야 한다.
먼저 addHandler()라는 메서드를 생성한다. 이 메서드는 DOM 레벨 접근법과 DOM 레벨 2 접근법, 인터넷 익스플로러 접근법 중 가능한 방법을 써서 이벤트 핸들러를 추가하며 EventUtil라는 객체에 등록된다. addHandler() 메서드는 매개변수요소, 이벤트 이름, 이벤트 핸들러 함수 세 가지를 받는다.
이벤트 핸들러를 제거하는 removeEventListener()도 같은 매개변수를 받는데 다른 방법을 쓸수 없을 때는 DOM 레벨 0 접근법을 사용한다.

 

 


13.3 event 객체
DOM과 관련된 이벤트가 발생하면 관련 정보는 모두 event라는 객체에 저장된다. 이 객체에는 이벤트가 발생한 요소, 이벤트 타입 같은 기본 정보는 물론 이벤트와 관련된 다른 데이터도 저장된다.


13.3.1 DOM event 객체
DOM 표준을 준수하는 브라우저에서 이벤트 핸들러에 전달되는 매개변수는 event 객체 하나뿐이다. HTML 속성을 통해 이벤트 핸들러를 할당했을 때는 event라는 변수가 event 객체 구실을 한다.
이벤트 핸들러 내부에서 this 객체는 항상 currentTarget의 값과 일치하며 target에는 이벤트의 실제 타깃만 포함된다. 이벤트 핸들러가 타깃에 직접 할당되었다면 this와 currnetTarget, target은 모두 같다.

preventDefault() 메서드는 이벤트의 기본 동작을 취소한다. preventDefault()로 이벤트를 취소하려면 해당 이벤트의 cancelabe 프로퍼티가 true여야 한다.

stopPropagation() 메서드는 이벤트 흐름을 즉시 멈춰서 이벤트 캡처링이나 버블링을 모두 취소한다. 이벤트 핸들러를 직접 추가하고 stopPropagation()을 호출해서 document.body에 등록된 이벤트 핸들러가 동작하지 않게 막을 수 있다.

eventPhase 프로퍼티는 현재 이벤트가 어느 단계에 있는지를 나타낸다. eventPhase는 이벤트 핸들러가 캡쳐단계에서 호출되었으면 1, 타깃에서 호출되었으면2, 버블링 단계에서 호출되었으면 3이다. "타깃"이 버블링 단계에 포함되긴 하지만 eventPhase는 항상 2이고 eventPhase가 2이면 this와 target, currentTarget은 항상 일치한다.

※ event 객체는 이벤트 핸들러가 아직 실행 중일 때만 존재하며 이벤트 핸들러가 실행을 마치면 event 객체는 파과된다.

 


13.3.2 인터넷 익스플로러의 event 객체
DOM 표준의 event 객체와 달리 인터넷 익스플로러의 event 객체는 이벤트 핸들러를 어떻게 할당했느냐에 따라 다르게 접근한다. 이벤트 핸들러를 DOM 레벨 0 접근법으로 할당하면 event 객체는 오로지 window 객체의 프로퍼티로만 존재하고 이벤트 핸들러를 attachEvent()로 할당하면 event 객체는 함수의 유일한 매개변수로 전달된다.

btn.onclick = function(){
  var event = window.event;
  alert(event.type); // "click"
}

btn.attachEvent("onclick", function(event)){
  alert(event.type); //"click"
}

HTML 속성에서 이벤트 핸들러를 할당하면 DOM 모델과 마찬가지로 event 객체는 event 변수에 저장된다.

<input type="button" value="Click Me" onclick = "alert(event.type)" /> 

이벤트 핸들러의 스코프는 할당 방식에 따라 다르므로 this 역시 항상 이벤트 타깃과 같지는 않는다. 항상 event.srcElement를 사용하는 것이 좋다. (event.srcElement === this)

returnValue 프로퍼티는 DOM 표준의 preventDefault() 메서드와 마찬가지로 주어진 이벤트의 기본 동작을 취소한다. 기본 동작을 취소하려면 returnValue를 false로 설정한다. (event.returnValue = false)

cancelBubblle 프로퍼티는 DOM 표준의 stopPropagation() 메서드와 마찬가지로 이벤트 버블링을 취소한다. IE8 및 이전 버전에서는 캡처링 단계를 지원하지 않으므로 버블링 단계만 취소된다. 버튼의 onclick 이벤트 핸들러에서 cancelBubblle을 true로 설정하면 이벤트가 document.body 이벤트 핸들러까지 버블링되어 올라가지 않는다.


13.3.3 크로스 브라우저 이벤트 객체
DOM 표준과 인터넷 익스플로러 event 객체가 서로 다르긴 하지만 익스플로러의 event 객체에 들어있는 정보와 기능은 모두 DOM 객체에 들어있으며 단지 형태가 다를 뿐이다.

 

 


13.4 이벤트 타입
DOM 레벨 3 이벤트는 이벤트를 다음과 같이 분류한다.

- 사용자 인터페이스(UI) 이벤트는 일반적인 브라우저 이벤트이며 BOM과의 상호 작용이 포함될 수 있다.
- 포커스 이벤트는 요소가 포커스를 얻거나 잃었을 때 발생한다.
- 마우스 이벤트는 마우스로 어떤 동작을 취할 때 발생한다.
- 휠 이벤트는 마우스 휠이나 이와 비슷한 장치를 사용할 때 발생한다.
- 텍스트 이벤트는 문서에 텍스트를 입력할 때 발생한다.
- 키보드 이벤트는 키보드로 어떤 동작을 취할 때 발생한다.
- 구성 이벤트는 입력 방법 에디터를 통해 문자를 입력할 때 발생한다.
- 변경 이벤트는 DOM 구조가 바뀔 때 발생한다.

이 외에 전용이벤트는 일반적으로 명세의 요건보다는 개발자의 필요에 따라 만들어지므로 브라우저에 따라 다르게 구현되며 인터넷 익스클로러 9를 포함해 주요 브라우저는 모두 DOM 레벨 2 이벤트를 지원한다.


13.4.1 UI 이벤트
UI 이벤트는 사용자와 직접 관련이 있지는 않다.

- DOMActivate - 사용자가 마우스나 키보드로 요소를 활성화했을 때 발생한다. click이나 keydown보다 범용적이나 DOM 레벨 3 이벤트에서 폐기되었다.
- load - 페이지를 완전히 불러왔을 때 window 에서, 모든 프레임을 완전히 불러왔을  때 프레임셋에서, 이미지나 객체를 완전히 불러 왔을때 <img> 요소나 <object>요소에서 발생한다.
- unload - 페이지를 완전히 종료했을 때 window에서, 모든 프레임을 완전히 종료했을 때 프레임셋에서, 객체를 완전히 종료햇을때 <object> 요소에서 발생한다.
- abort - <object> 요소의 콘텐츠를 완전히 내려받기 전에 사용자가 취소했을 때 해당 요소에서 발생한다.
- error -  자바스크립트 에러가 발생했을 때 window에서, 이미지를 불러올 수 없을때 해당 <img> 요소에서, <object>요소에서. <object> 요소 콘텐츠를 불러올 수 없을 때 해당 요소에서 프레임을 불러올 수 없을 때 해당 프레임셋에서 발생한다.
- select - 사용자가 텍스트 박스<input>이나 <textarea>에서 글자를 선택할 때 발생한다.
- resize - window나 프레임의 크기를 바꿀 때 발생한다.
- scroll - 사용자가 스크롤바 있는 요소를 스클롤할 때 발생한다. <body> 요소에는 페이지 전체에 대한 스크롤바가 있다.

DOMActivate를 제외하면 이들 이벤트는 DOM 레벨 2 이벤트의 HTML 이벤트 그룹에 속한다.(DOMActivate는 아직 DOM 레벨 2의 UI 이벤트에 속한다.)

 

load 이벤트
window 객체의 load 이벤트는 이미지나 자바스크립트 파일, CSS 파일 같은 외부 자원을 포함해 전체 페이지를 완전히 불러왔을 때 발생한다. onload 이벤트 핸들러는 두 가지 방법으로 정의할 수 있는데 첫 번째 방법은 자바스크립트를 이용하는 방법이고 다른 방법은 <body> 요소에 onload 속성을 추가하는 것이다. 가능한 한 자바스크립트 접근법을 사용하길 권한다.

※ DOM 레벨 2 이벤트에서는 load 이벤트를 window 가 아니라 document에서 발생하도록 정했다. 하지만 하위 호환성 때문에 모든 브라우저가 load 이벤트를 window에도 구현한다. 문서에 포함된 이미지에는 모두 HTML에서 onload 이벤트 핸들러를 직접 할당할 수 있고 자바스크립트에서 지정할 수도 있다.

※ 인터넷 익스플로러 8 및 이전 버전에서는 load 이벤트가 발생할 때 DOM에 포함되지 않은 이미지에 대해서는  event 객체를 생성하지 않았다. 이는 문서에 추가되지 않은 <img>요소 및 Image 객체에 모두 적용된다. 이 문제는 인터넷 익스플로러 9에서 수정되었다.


unload 이벤트
unload 이벤트는 load 이벤트와 반대로 문서를 완전히 닫을 때 발생한다. unload 이벤트는 일반적으로 다른 페이지로 이동할 때 발생하며 주로 각종 참조를 제거하여 메모리 누수를 방지하는 목적으로 사용한다. load 이벤트와 같이 두 가지 방법으로 할당이 가능한데 첫 번째 방법은 자바스크립트를 이용하는 방법이고 두 번째 방법은 <body> 요소에 이벤트 핸들러 속성을 추가하는 방법이다. unload 이벤트는 모든것이 해제될 때 발생하므로 페이지에 존재하던 객체를 전부 사용할 수 없다.

※ DOM 레벨 2 이벤트에서는 unload 이벤트가 window가 아닌 <body>에서 발생한다고 정의한다. 하지만 하위 호환성 때문에 모든 브라우저는 unload 이벤트를 window에 구현한다.


resize 이벤트
브라우저 창의 사이즈를 바꾸면 resize 이벤트가 발생한다. 이 이벤트는 window에서 발생하므로 이벤트 핸들러를 할당할 때 자바스크립트를 쓸 수도 있고 <body> 요소에 onresize 속성을 추가해도 된다. resize 이벤트는 인터넷 익스플로러와 사파리, 크롬, 오페라에서는 1픽셀이라도 바뀌는 즉시 발행하며 사용자가 브라우저 창 크기를 조절하는 동안 계속 발생하지만 파이어폭스에서는 창 크기 조절을 멈추는 시점에서 발생한다.


scroll 이벤트
쿽스 모드에서는 <body> 요소의 scrollLeft와 scrollTop을 통해 얼마나 스크롤했는지 알 수 있으며 표준 모드에서는 사파리를 제외한 모든 브라우저에서 <html>요소의 scrollLeft와 scrollTop을 통해 얼마나 스크롤했는지 알 수 있다. 문서를 스크롤하는 동안 반복 실행된다.

 


13.4.2 Focus 이벤트
포커스 이벤트는 요소가 포커스를 받거나 잃을때 발생하며 이들 이벤트와 document.hasFocus(), document.activeElement 프로퍼티를 조합하면 사용자가 페이지를 어떻게 움직이는지 알수 있다.

- blur - 요소가 포커스를 잃을 때 발생한다. 이 이벤트는 버블링되지 않으며 모든 브라우저에서 지원된다.
- DOMFocusIn - 요소가 포커스를 받을 때 발생한다. 이 이벤트는 HTML 이벤트 focus의 버블링 버전으로 오페라만 지원한다. DOM 레벨 3 이벤트는 대신 focusin를 권장한다.
- DOMFocusOut -  요소가 포커스를 잃을 때 발생한다. 이 이벤트는 HTML 이벤트 blur의 범용 버전으로 오페라만 지원한다. DOM 레벨 3 이벤트는 focusout을 권장한다.
- focus - 요소가 포커스를 받을 때 발생한다.  이 이벤트는 버블링되지 않으며 모든 브라우저에서 지원된다.
- focusin - 요소가 포커스를 받을 때 발생한다. HTML이벤트 focus의 버블링 버전이며 IE5.5 이상, 사파리 5.1 이상, 오페라 11.5이상, 크롬에서 지원한다.
- focusout - 요소가 포커스를 잃을 때 발생한다. HTML이벤트 blur의 범용 버전이며 IE5.5이상, 사파리 5.1 이상, 오페라 11.5이상, 크롬에서 지원한다.

 

이 그룹의 우선적 이벤트는 focus와 blur이며 자바스크립트 초기부터 지원되었다. 이 두 이벤트의 가장 큰 문제는 버블링 되지 않는것이고 이 때문에 인터넷 익스플로러는 focusin과 focusout을 도입했다. 포커스가 요소에서 다른 요소로 이동할 때는 다음 순서로 이벤트가 발생한다.

1. 포커스를 잃는 요소에서 focusout이 발생한다.
2. 포커스를 받는 요소에서 focusin이 발생한다.
3. 포커스를 잃는 요소에서 blur가 발생한다.
4. 포커스를 잃는 요소에서 DOMFocusOut이 발생한다.
5. 포커스를 받는 요소에서 focus가 발생한다.
6. 포커스를 받는 요소에서 DOMFocusIn이 발생한다.

 

※ focus와 blur는 버블링되지는 않지만 캡처링 단계에서 가로챌 수 있다.  

 


13.4.3 마우스 이벤트와 휠 이벤트
DOM 레벨 3 이벤트에 정의된 마우스 이벤트는 아홉가지이다.

- click - 사용자가 주요 마우스 버튼(일반적으로 왼쪽 버튼)을 클릭하거나 엔터키를 누를 때 발생한다. onclick 이벤트 핸들러가 키보드와 마우스에 모두 반응한다는 점은 접근성 구현에 중요하다.
- dbclick - 사용자가 주요 마우스 버튼을 더블 클릭할 때 발생한다.
- mousedown - 사용자가 마우스 버튼을 누를 때 발생한다.
- mouseenter - 마우스 커서가 요소 밖에서 요소 경계 안으로 처음 이동할 때 발생한다. 이 이벤트는 버블링되지 않으며 커서가 자손 요소 위에 올라갈 때 발생하지 않는다.
- mouseleave - 마우스 커서가 요소 위에 있다가 요소 경계 밖으로 이동할 때 발생한다. 이 이벤트는 버블링되지 않으며 커서가 자손 요소 위에 올라갈 때 발생하지도 않는다.
- mousemove - 마우스 커서가 요소 주변을 이동하는 동안 계속 발생한다.
- mouseout - 마우스 커서가 요소 위에 있다가 다른 요소 위로 이동할 때 발생한다.'다른 요소'는 요소의 경계 밖에 있는 요소일 수도 자식 요소일수도 있다.
- mouseover - 마우스 커서가 요소 바깥에 있다가 경계 아느로 이동할 때 발생한다.
- mouseup - 사용자가 마우스 버튼을 누르고 있다가 놓을 때 발생한다.

 

mouseenter와 mouseleave를 제외하면 모든 마우스 이벤트가 버블링되어 올라가며 모든 마우스 이벤트는 취소할 수 있고 브라우저 기본 동작에 영향을 미친다. 이들 네 가지 마우스 이벤트는 항상 다음 순서대로 발생한다.

mousedown > mouseup > click > mousedown > mouseup > click > dbclick

click과 dbclick은 다른 이벤트에 영향을 받지만 mousedown, mouseup은 다른 이벤트에 영향을 받지 않는다.
마우스 이벤트에는 '휠 이벤트'라는 부속 그룹이 있는데 휠 이벤트 그룹은 mousewheel 이벤트 하나뿐이며 마우스 휠이나 맥 트랙패드처럼 이와 비슷한 장치에서 발생한다.


클라이언트 좌표
마우스 이벤트는 모든 브라우저 뷰포트의 어느 위치에서 발생한다. 이 정보는 event 객체의 clientX, clientY 프로퍼티에 저장되는데 이들 프로퍼티는 이벤트 당시 마우스 커서의 위치를 나타내며 모든 브라우저에서 지원한다.


페이지 좌표
클라이언트 좌표는 뷰포트 기준으로 어디에서 일어났는지 나타내는데 반해 '페이지 좌표'는 페이지 기준이며 event 객체에 pageX, pageY 프로퍼티로 저장된다. 퀵스 모드에서는 document.body, 표준모드에서는 document.documentElement의 scrollLeft/scrollTop 프로퍼티를 이용해서 계산한다.


화면 좌표
전체 화면을 기준으로 한 마우스 위치는 screenX/screenY 프로퍼티에 저장된다.


키보드 수정
'수정 키'는 Shift, Ctrl, Alt, Meta 키이며 이들은 종종 마우스 이벤트의 동작에 영향을 끼친다. DOM 표준에는 이들 키의 상태를 나타내는 shiftKey, ctrlKey, altKey, metaKey 네 가지 프로퍼티가 있다. 각 프로퍼티는 키를 누른 상태일 때 true, 그렇지 않다면 false인 불리언 값이다.

※ 인터넷 익스플로러 8 및 이전 버전은 metaKey 프로퍼티를 지원하지 않는다.


관련요소
mouseover와 mouseout 이벤트는 마우스 커서가 한 요소의 경계 안에서 다른 요소의 경계 안으로 이동할 때 발생한다. mouseover 이벤트에서 이벤트의 우선적 타깃은 커서가 이동하는 목적지 요소이며 '관련요소'는 커서가 출발하는 출발점 요소이다. mouseout의 우선적 타깃은 출발점 요소이며 관련 요소는 목적지 요소이다.
DOM 표준에서는 관련 요소에 관한 정보를 event 객체의 relatedTarget 프로퍼티로 제공하는데 mouseover와 mouseout 이벤트에서만 값을 가지며 다른 이벤트에서는 null이다.


버튼
click 이벤트는 요소에서 마우스 기본 버튼을 클릭하거나 엔터 키를 눌렀을 때만 발생하므로 어떤 버튼인지에 대한 정보는 필요하지 않다. mousedown과 mouseup 이벤트는 event 객체에 어떤 버튼을 누르거나 뗐는지 나타내는 button 프로퍼티가 있다. DOM 표준의 button 프로퍼티에는 세 가지 값이 있는데 0은 마우스 기본 버튼(보통 왼쪽), 1은 마우스 가운데 버튼(보통 스크롤 휠 버튼), 2는 두 번째 마우스 버튼(보통 오른쪽)을 나타낸다.

※ onmouseup 이벤트 핸들러에서 사용할 경우 button 의 값은 지금 막 손을 뗀 버튼의 값이다.


추가적인 이벤트 정보
DOM 레벨 2 이벤트 명세에는 event 객체에서 추가 정보를 제공하는 detail 프로퍼티가 존재한다. detail 초기값은 1이며 클릭할 때마다 늘어난다. mousedown과 mouseup 사이에 마우스를 움직였다면 detail은 0으로 초기화 된다.


mousewheel 이벤트
이 이벤트는 사용자가 마우스 휠을 세로 방향으로 움직일 때 발생한다. mousewheel 이벤트의 event 객체에는 마우스 이벤트에 관한 표준 정보 외에도 wheelDelta 라는 추가 프로퍼티가 있는데 마우스 휠을 앞으로 굴리면 wheelDelta는 120의 배수인 양수이고 뒤로 굴리면 wheelDelta는 120의 배수인 음수이다.


터치 장치 지원

- dbclick 이벤트는 전혀 지원되지 않는다.
- 클릭 가능한 요소를 탭하면 mousemove 이벤트가 발생한다. 탭한 결과로 컨텐츠가 바뀌면 이벤트는 더 이상 발생하지 않는다.
- mousemove 이벤트도 mouseover와 mouseout 이벤트를 발생시킨다.
- mousewheel과 scroll 이벤트는 화면에 두 손가락을 올릴 때 발생하며 손가락을 움직이면 페이지가 스크롤된다.


접근성 문제
웹 애플리케이션이나 웹사이트를 접근성 있게, 특히 스크린 리더 사용자가 쓰기 쉽게 만들려면 마우스 이벤트를 조심해서 사용해야 한다.

- 코드 실행에는 click을 이용한다. 일부는 애플리케이션 코드를 onmousedown에서 실행하면 더 빠르다고 하는데 시각에 문제가 없는 사용자에게는 이 말도 맞지만 스크린 리더 사용자는 mousedown 이벤트를 발생시킬수 없으므로 이 코드는 사용 불가능하다.

- 사용자에게 새 옵션을 제시할 때 onmouseover를 사용해서는 안된다. 새 옵션을 이런식으로 표현해야 한다면 정보를 키보드 단축키에도 할당해야 한다.

- 중요한 동작을 dbclick으로 실행해서는 안된다. 키보드로는 이 이벤트를 발생시킬 수 없다.

 

※ 웹 페이지의 접근성에 대해 더 읽어보려면 http://webaim.orghttp://accessibility.yahoo.com을 참고하길 바란다.

 

 

13.4.4 키보드와 텍스트 이벤트
'키보드 이벤트'는 사용자가 키보드를 조작할 때 발생한다.

- keydown - 사용자가 키를 처음 누를 때 발생하며 누르고 있는 동안 계속 발생한다.
- keypress - 사용자 키를 누른 결과로 문자가 입력되었을 때 처음 발생하며 누르고 있는 동안 계속 발생한다. 이 이벤트는 Esc 키에서도 발생한다. DOM 레벨 3 이벤트에서는 keypress 이벤트를 폐기했으며 대신  textInput 이벤트를 권장한다.
- keyup -  사용자가 키에서 손을 뗄 때 발생한다.

 

모든 요소가 이들 이벤트를 지원하지만 텍스트 박스에 가장 많이 쓰인다. 텍스트 이벤트는 textInput 하나뿐이다. 이 이벤트는 keypress를 확장하여 텍스트 입력이 사용자에게 표시되기 전에 가로챌 의도로 만들어졌고 텍스트가 텍스트 박스에 삽입되기 직전에 발생한다.
사용자가 글자 키를 누르면 keydown, keypress, keyup 순서로 이벤트가 발생하는데 keydown과 keypress는 모두 텍스트 박스에 글자가 나타나기 전에 발생하지만 keyup 이벤트는 텍스트 박스에 글자가 나타난 후에 발생한다. 키를 누르고 있으면 손을 뗄때까지 keyup 이벤트가 발생한다.

※ 키보드 이벤트는 마우스 이벤트와 같은 수정 키를 지원한다. shiftKey, ctrlKey, altKey, metaKey 프로퍼티는 모두 키보드 이벤트에도 존재한다. 인터넷 익스플로러 0 및 이전 버전은 metaKey를 지원하지 않는다.


키코드
keydown과 keyup 이벤트에서 event 객체의 keyCode 프로퍼티에는 각 키에 대응하는 코드가 들어있다. 알파벳과 숫자 키의 keyCode는 해당 키의 소문자 또는 숫자의 ASCII 값이다.


문자코드
keypress 이벤트가 일어났다는 것은 해당 키가 화면에 표시된다는 뜻이다. 모든 브라우저는 글자를 삽입하거나 제거하는 키에서 keypress 이벤트를 발생시키며 기타 키에서는 브라우저에 따라 다르다.
인터넷 익스플로러 9 이상, 파이어폭스, 크롬, 사파리는 keypress 이벤트에서만 event 객체에서 charCode라는 프로퍼티를 지원한다. 이 프로퍼티에는 관련된 키 문자의 ASCII 코드가 들어있는데 일반적으로 0 또는 해당 키의 키코드이다.


DOM 레벨 3에서 바뀐점
DOM 레벨 3 이벤트에서는 키보드 이벤트에서 몇 가지를 바꿨다. charCode 프로퍼티를 폐기하고 keychar 두 가지 프로퍼티를 추가했다. key 프로퍼티는 keyCode를 교체할 의도로 도입했으며 문자열을 포함한다. 문자 키를 누르면 key 값은 해당 문자(예를 들어 "k"나 "M") 이며 문자가 아닌 키를 누르면 키 이름("shift"나 "Down")이다. char 프로퍼티는 문자 키에서는 key와 같으며 문자가 아닌 키에서는 null이다.
DOM 레벨 3 이벤트에서는 location라는 프로퍼티도 추가했는데 이는 키를 어디에서 눌렀는지 나타내는 숫자형 값이다.
event 객체에 추가된 마지막은 getModifierState() 메서드인데 매개변수로 Shift, Control, Alt, Meta 중 하나를 받고 이는 체크할 수정 키를 나타내는 문자열이다. 주어진 키가 눌려 있는 상태라면 true를 반환하고 그렇지 않다면 false를 반환한다.


textInput 이벤트
DOM  레벨 3 이벤트 명세에서는 편집 가능한 영역에 문자가 입력될 때 발생하는 textInput 이라는 이벤트를 추가했다. 이 이벤트는 keypress를 교체할 목적으로 디자인되었지만 차이점 중 하나는 keypress 이벤트가 포커스를 받을 수 있는 요소 전체에서 지원되는데 반해 textInput 이벤트는 편집 가능한 영역에서만 지원된다. textInput 이벤트는 문자에만 관심이 있으므로 event 객체의 data 프로퍼티에는 문자 코드가 아니라 삽입 문자 자체가 저장된다.

 

 

13.4.5 조합 이벤트
'조합 이벤트'는 DOM 레벨 3 이벤트에서 처음 도입되었으며 일반적으로 IME에 사용되는 복잡한 입력을 처리하도록 만들어졌다. IME는 일본어 등 사용자가 물리적인 키보드에 존재하지 않는 문자를 입력하도록 만들어졌다.

- compositionstart - IME의 텍스트 조합 시스템이 열리는 순간 발생하며 곧 문자가 입력될 것을 나타냄
- compositionupdate - 입력 필드에 새 문자가 삽입될 때 발생함
- compositionend - 텍스트 조합 시스템이 닫힐 때 발생하며 일반적인 키보드 입력으로 돌아갈 것을 나타냄

 


13.4.6 matation event
DOM 레벨 2에서는 DOM의 일부가 바뀌었을 때 알리는 변경 이벤트를 제공한다. 변경 이벤트는 특정 언어에 종속되지 않고 XML이나 HTML DOM에서 모두 동작하도록 디자인되었다.

- DOMSubtreeModified - DOM 구조가 어떻게든 바뀌었을 때 발생한다. 이 이벤트는 다른 이벤트가 모두 발생한 후에 발생한다.
- DOMNodeInserted -  노드가 다른 노드의 자식으로 삽입될 때 발생한다.
- DOMNodeRemoved - 노드가 부모 노드로부터 제거될 때 발생한다.

인터넷 익스플로러 8 및 이전 버전은 변경 이벤트를 지원하지 않는다.


노드 제거
removeChild()replaceChild()로 DOM에서 노드를 제거하면 가장 먼저 DOMNodeRemoved 이벤트가 발생한다. 이 이벤트 타깃은 제거된 노드이며 event.relatedNode 프로퍼티에는 부모 노드에 대한 참조가 들어있다.


노드 삽입
appendChild()replaceChild(), insertBefore()로 노드를 DOM에 삽입하면 DOMNodeInserted 이벤트가 가장 먼저 발생한다. 이 이벤트의 타깃은 삽입된 노드이며 event.relatedNode 프로퍼티에는 부모 노드에 대한 참조가 들어 있다. 이 이벤트가 발생하는 시점에서 해당 노드는 이미 부모 노드에 추가된 상태이고 이 이벤트는 버블링되므로 조상 요소 어디에든 위임해 처리할 수 있다.

 


13.4.7 HTML5 이벤트
contextmenu 이벤트
개발자들이 어떤 동작(윈도우에서는 오른쪽 클릭, 맥에서는 Ctrl+클릭)에서 컨텍스트 메뉴를 표시할 것인지 기본 컨텍스트 메뉴와 충돌하지 않게 하려면 어떻게 할 것인지를 해결하기 위해 contextmenu 이벤트가 도입되었다. 이 이벤트는 버블링되므로 document에 이벤트 핸들러 하나만 할당해서 페이지에서 발생하는 contextmenu 이벤트를 모두 처리할 수 있다. contextmenu 이벤트는 마우스 이벤트로 간주되므로 커서 위치와 관련된 프로퍼티를 모두 포함한다. 일반적으로 oncontextmenu 이벤트 핸들러에서 커스텀 컨텍스트 메뉴를 표시하고 onclick 이벤트 핸들러에서 다시 숨긴다. 이 이벤트는 인터넷익스플로러, 파이어폭스, 사파리, 크롬, 오페라11 이상에서 지원된다.


beforeunload 이벤트
이 이벤트는 window에서 발생하며 개발자에게 페이지에서 떠나지 못하게 막을 방법을 제공할 의도로 만들어졌다. 브라우저가 페이지를 언로드하기 직전에 발생하며 페이지를 언로드 하겠다고 확인하지 않으면 계속 머무르게 한다. 이 이벤트는 취소할 수 없는데 취소를 허용한다면 사용자가 페이지를 떠나지 못하게 강제하는 것이나 마찬가지이기 때문이다. 오페라는 버전 11까지 이 이벤트를 지원하지 않는다.


DOMContentLoaded 이벤트
window의 load 이벤트는 페이지를 완전히 불러와야 발생하므로 외부 자원이 많이 포함된 페이지에서는 시간이 걸릴 수 있는데 DOMContentLoaded 이벤트는 DOM 트리가 완전히 구성되는 즉시 발생하므로 load 이벤트보다 먼저 이벤트 핸들러를 등록할 수 있다. DOMContentLoaded 이벤트 핸들러는 document와 window에 모두 등록할 수 있다.(이벤트타깃은 document지만 window로 버블링된다)


redadystatechange 이벤트
이 이벤트의 의도는 문서나 요소를 불러오는 상황에 대한 정보를 제공하고자 하는 것이고 redadystatechange 이벤트를 지원하는 각 객체에는 readyState 프로퍼티가 있으며 그 값은 다음 문자열 중 하나이다.

- uninitialized - 객체가 존재하지만 초기화되지 않음
- loading - 객체에서 데이터를 불러오는 중
- loaded - 객체에서 데이터를 완전히 불러옴
- interactive -  객체를 완전히 불러오지는 못했지만 상호 작용은 가능함
- complete -  객체를 완전히 불러옴

redadystatechange 이벤트는 종종 네 번 이하로 발생하며 readyState 값이 항상 같은 순서로 진행하지는 않는다.

 

 

13.4.8 장치 이벤트
스마트폰과 태블릿 장치가 보급되면서 사용자들은 새로운 방식으로 브라우저를 이용하기 시작했고 이에따라 새 이벤트 그룹이 만들어졌다. 장치 이벤트는 장치를 어떻게 사용하고 있는지에 관한 정보를 제공한다.


orientationchange 이벤트
애플은 모바일 사파리에 orientationchange 이벤트를 도입했는데 이는 사용자가 장치를 가로 모드나 세로 모드로 바꿀 때 발생한다. 모바일 사파리에는 window.orientation 프로퍼티가 있는데 0은 세로모드, 90은 왼쪽 가로 모드(홈 버튼이 오른쪽 위치), -90은 오른쪽 가로 모드(홈 버튼이 왼쪽에 있는)를 각각 나타내고 사용자가 장치 방향을 바꿀 때마다 orientationchange 이벤트가 발생한다.  IOS 장치는 모두 orientationchange 이벤트와 window.orientation 프로퍼티를 지원한다.

※ orientationchange는 window 이벤트로 간주하므로 orientationchange <body> 요소에 속성으로 추가해도 이벤트 핸들러가 할당된다


MozOrientation 이벤트
파이어폭스 3.6은 장치 방향을 감지하는 MozOrientation라는 새 이벤트를 도입했는데 이 이벤트 장치에 부착된 가속도계가 장치 방향이 바뀌었음을 감지할 때 발생한다. event 객체에는 가속도계의 세 가지 데이터를 나타내는 x,y,z 프로퍼티가 있고 각 값은 -1과 1 사이의 숫자이며 서로 다른 축을 나타낸다. MozOrientation 이벤트는 가속도계가 부착된 장치 맥북, 레노보 씽크 패드, 윈도 모바일 및 안드로이드 장치에서 지원된다.


deviceorientation 이벤트
이 이벤트는 장치 방향 이벤트 명세에 정의되어 있으며 가속도계가 부착된 장치에서 관련 있는 동작을 감지했을때 window에서 발생한다. deviceorientation 이벤트의 목적은 장치의 방향을 감지하는 것이지 움직임을 감지하는 것은 아니다. event 객체에는 다섯 가지 프로퍼티(alpha, beta, gamma, absolute, compassCalibrated)가 존재한다.


devicemotion 이벤트
이 이벤트는 장치가 실제로 움직이고 있을 때 발생하고 이벤트가 발생하면 event 객체에는 acceleration, accelerationIncludingGravity, interval, rotationRate 프로퍼티가 추가된다.

 

13.4.9 터치와 제스처 이벤트
터치 이벤트는 손가락을 화면에 댈 때, 화면을 따라 드래그할 때, 화면에서 손을 뗄때 발생한다.

- touchstart - 손가락으로 화면을 터치할 때 발생하며 이미 다른 소노가락을 화면에 대고 있어도 다른 손가락을 대면 발생한다.
- touchmove -  손가락을 화면에서 움직일 때 계속 발생하며 이벤트가 일어나는 동안 preventDefault()를 호출하면 스크롤을 막을수 있다.
- touchend - 손가락을 화면에서 뗄 때 발생한다.
- touchcancel - 시스템에서 터치를 더이상 추적하지 않을 때 발생한다.

 

 

각 이벤트는 버블링 되어 올라가며 취소 가능하다. 터치 이벤트는 DOM 명세의 일부는 아니나 명세와 호환되도록 구현되어 터치이벤트의 event 객체에는 마우스 이벤트와 공통인 bubbles, cancelable, view, clientX, clientY, screenX, screenY, derail, altKey, ctrlKey, meraKey 프로퍼티가 들어있으며 이 외에도 터치를 추적하는 touches, targetTouches, changedTouches 프로퍼티가 들어있다. 요소에 탭 했을때 이벤트가 일어나는 순서는 touchstart, mouseover, mousemove, mousedown, mouseup, click, touchend 이다.


제스처 이벤트
'제스처'란 두 손가락으로 화면을 터치한 채 표시된 부분의 크기를 바꾸거나 회전하는 동작을 말한다.

- gesturestart - 한 손가락을 화면에 얹은 채 다른 손가락으로 화면을 터치할 때 발생한다.
- gesturechange - 화면에서 두 손가락 중 하나의 위치가 바뀔 때 발생한다.
- gestureend - 두 손가락 중 하나를 화면에서 뗄 때 발생한다.

 

이들 이벤트는 두 손가락으로 이벤트 대상을 터치할 때만 발생한다. event 객체에 추가 되는 프로퍼티는 rotation과 scale이다.

※ 터치 이벤트도 rotation과 scale 프로퍼티를 반환하긴 하지만 이 값은 두 손가락이 화면에 닿아 있을 때에만 사용한다. 일반적으로 터치 이벤트의 복잡한 상호작용을 모두 추적하기보다는 제스처 이벤트를 쓰는 편이다.

 

 

 

13.5 메모리와 성능
최신 웹 애플리케이션에서 상호작용을 담당하는 것이 핸들러이긴 하지만 자바스크립트에서는 페이지에 존재하는 이벤트 핸들러의 개수가 페이지에 직접적으로 영향을 미친다. 그 첫번째 이유는 각 함수가 메모리를 점유하는 객체이기 때문이고 두 번째는 이벤트 핸들러를 많이 할당하려면 DOM 접근도 많아지며 전체 페이지의 응답성을 떨어 뜨리기 때문이다.


13.5.1 이벤트 위임
"이벤트 핸들러 개수" 문제의 해결책은 '이벤트 위임'이라는 방법이다. 이벤트 위임은 이벤트 버블링의 장점을 활용하여 이벤트 핸들러를 하나만 할당해서 해당 타입의 이벤트를 모두 처리하는 테크닉이다.  이벤트 위임을 적용하기에 알맞는 이벤트는 click, mousedown, mouseup, keydown, keyup, keypress가 있다.


13.5.2 이벤트 핸들러 제거
이벤트 핸들러를 요소에 할당하면 브라우저 코드와 자바스크립트 코드가 연결되는데 이런 연결이 많을수록 페이지가 느려진다. 이 문제를 해결하는 방법은 이벤트 위임을 통해 연결 개수를 제한하는 것이고 다른 방법은 더이상 사용하지 않은 잔류 핸들러를 제거하는 것이다. 이 문제는 요소에서 이벤트 핸들러를 제거하지 않은 채 요소만 문서에서 제거하는 경우 DOM 표준 메서드인 removeChild()나 replaceChild()에서도 간혹 일어나긴 하지만 innerHTML로 페이지 일부를 교체할 때 자주 일어난다.
페이지를 떠나기 전 제거하지 않은 이벤트 핸들러는 메모리에 계속 남게 되므로 페이지를 떠나기 전에 onunload 이벤트 핸들러를 써서 이벤트 핸들러를 모두 제거하는 편이 좋다.

※ onunload 이벤트 핸들러를 사용하면 페이지는 결코 bfcache에 저장되지 않음을 염두해야 한다. bfcache를 이용하는 편이 낫다고 판단한다면 onunload로 이벤트 핸들러를 제거하는 작업은 인터넷 익스플로러에서만 하는 방법도 있다.

 

 

 

13.6 이벤트 시뮬레이션

13.6.1 DOM 이벤트 시뮬레이션
document에서 createEvent() 메서드를 호출하여 언제든 event 객체를 생성할 수 있다. 이 메서드는 생성할 이벤트 타입을 나타내는 문자열을 매개변수로 받았다. event 객체를 생성하면 이벤트에 관한 정보를 이용해 초기화해야 하는데 각 타입의 event 객체에는 적절한 데이터를 넘겨 초기화하는 메서드가 존재한다. 메서드 이름은 createEvent()에 넘긴 매개변수마다 다르다
이벤트 시뮬레이션의 마지막 단계는 이벤트를 발생시키는 것이고 이벤트 발생은 dispatchEvent() 메서드를 통하는데 이벤트를 지원하는 DOM 노드에는 모두 이 메서드가 존재한다. dispatchEvent() 메서드는 발생시킬 이벤트를 표현하는 event 객체를 매개변수로 받는다.


13.6.2 인터넷 익스플로의 이벤트 시뮬레이션
익스플로러8 및 이전 버전의 이벤트 시뮬레이션도 event 객체를 생성하고 적절한 정보를 할당한 후 해당 객체를 이용해 이벤트를 발생시킨다. document의 createEventObject() 메서드로 event 객체를 생성하는데 매개변수를 받지 않으며 범용 event 객체를 반환한다. 반환받은 객체에 필요한 프로퍼티를 반드시 직접 할당해야 하는데 모두 할당했으면 마지막으로 타깃에서 fireEvent()를 호출한다. 이 메서드는 매개변수로 이벤트 핸들러 이름과 event 객체 두 가지를 받는데 secElement와 type 프로퍼티는 자동으로 할당되지만 다른 프로퍼티는 반드시 직접 할당해야 한다.

 

 

 

'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

20장 JSON  (0) 2015.03.24
14장 폼스크립트  (0) 2015.03.18
DOM 확장  (0) 2014.12.18
DOM  (0) 2014.12.08
클라이언트 감지  (0) 2014.11.20

DOM 확장

2014. 12. 18. 18:16 나홀로스터디/JS For Web Dev

 

11장 DOM 확장

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
- 선택자 API에 대한 이해
- HTML5 DOM 확장 사용
- 브라우저 전용 DOM 확장 사용


DOM은 그 자체로도 매우 잘 정의된 API이긴 하지만 표준 기반 방법이나 특정 브라우저 전용 방법으로 확장하여 기능을 추가할 때도 많다. DOM 확장의 우선적 표준은 선택자 API와 HTML5 두 가지이다.


11.1 선택자 API
자바스크립트 라이브러리에서 가장 인기있는 기능은 CSS 선택자로 패턴을 만들고 그에 맞는 DOM 요소를 선택하는 능력이다. 그 중에서도 jQuery 라이브러리는 getElementById()나 getElementsByTagName()으로 요소에 대한 참조를 얻지 않고 완전히 CSS 선택자에 기초하여 DOM 문서를 쿼리한다.
선택자 API 레벨 1의 핵심은 querySelector()querySecectorAll() 메서드이다. 지원하는 브라우저에서는 Document 타입과 Element 타입에서 이 메서드를 사용할 수 있다.


11.1.1 querySelector() 메서드
querySelector() 메서드는 매개변수CSS 쿼리를 받고 패턴에 일치하는 첫 번째 자손 요소를 반환하며 일치하는 것이 없다면 null을 반환한다.

var body = document.querySelector('body'); 


11.1.2 querySelectorAll() 메서드
querySelectorAll() 메서드는 querySelector()와 마찬가지로 CSS 쿼리를 매개변수로 받되 일치하는 노드 전체를 반환한다. 이 메서드는 NodeList의 정적 인스턴스를 반환한다. 다시 말해 반환 값은 NodeList의 프로퍼티와 메서드를 모두 갖지만 접근할 때마다 다시 쿼리하는 것이 아니라 처음 접근했을 때의 상태만 반영한 채 고정된다. 유효한 CSS를 넘겨 querySelector()을 호출하면 NodeList 객체를 반환하며 포함하는 요소 숫자에는 제한이 없다. 일치하는 것이 없다면 빈 NodeList를 반환한다.


11.1.3 matchesSelector() 메서드
선택자 API  레벨2 명세에서는 Element 타입에 matchesSelector()라는 메서드를 정의했다. 이 메서드는 매개변수로 CSS 선택자를 받고 요소가 그에 일치하면 true를 일치하지 않으면 false를 반환한다.

 

11.2 요소 간 이동
인터넷 익스플로러는 타 브라우저와 달리 요소 사이의 공백을 텍스트 노드로 반환하지 않는다. 이 때문에 childNodes나 firstChild 같은 프로퍼티를 사용할 때 차이가 발생했고 DOM 명세를 유지하면서 브라우저 사이의 차이를 극복하려는 노력으로 요소 간 이동 명세서에서는 새 프로퍼티 그룹을 정의했다.

childElemnetCount - 자식 요소 숫자를 반환하되 텍스트 노드와 주석은 제외한다.
firstElementChild -  첫 번째 자식 요소를 가리킨다.
lastElementChild - 마지막 자식 요소를 가리킨다.
previousElementSibling - 이전 형제 요소를 가리킨다.
nextElementSibling - 다음 형제 요소를 가리킨다.

 

11.3 HTML5
HTML5에서 다루는 주제는 매우 방대하며 이 섹션에서는 DOM 노드 전체와 관련있는 부분만 설명한다. HTML5의 다른 부분은 관련된 주제가 등장할 때마다 설명한다.


11.3.1 클래스 관련 추가사항
HTML4 이래 웹에서 가장 많이 바뀐 점이라면 class 속성을 통해 요소의 시맨틱 정보와 스타일 정보를 함께 전달하는 사례가 늘어났다는 점이다.


getElementsByClassName() 메서드
HTML5에서 가장 인기있는 것은 document 객체와 HTML 요소 전체에서 사용 가능한 getElementsByClassName() 메서드이다.  getElementsByClassName() 메서드는 클래스 이름 문자열을 매개변수로 받으며 해당 클래스를 모두 가진 요소의 NodeList를 반환하므로 이 메서드는 클래스를 바탕으로 이벤트를 등록하려 할 때 유용하다.


classList 프로퍼티
클래스 이름을 조작할 때는 className 프로퍼티를 이용해 중복여부를 확인하고 클래스 이름을 추가하거나 제거, 교체했다. HTML5에서는 모든 요소에 classList 프로퍼티를 추가하여 클래스 이름을 안전하고 단순하게 조작할 수 있다. clasList 프로퍼티는 DOMTokenList란 새 컬렉션 타입의 인스턴스이다. 다른 DOM 컬렉션과 마찬가지로 DOMTokenList 역시 length 프로퍼티가 있어서 포함된 데이터 개수를 알수 있고 item() 메서드나 대괄호 표기법을 통해 개개의 데이터를 가져올 수 있다.

add(value) - 주어진 문자열 값을 목록에 추가한다. 값이 이미 존재하면 추가하지 않는다.
contains(value) - 주어진 값이 목록에 존재하면 true를 그렇지 않다면 false를 반환한다.
remove(value) - 주어진 문자열 값을 목록에서 제거한다.
toggle(value) - 값이 목록에 존재하면 제거하고 그렇지 않으면 추가한다.
div.classList.remove("user");
div.classList.toggle("user");

classList 프로퍼티를 이용하면 요소의 class 속성을 완전히 제거하거나 덮어쓸 때 외에는 className 프로퍼티가 불필요하다.


11.3.2 포커스 관리
HTML5는 DOM에 포커스 관리 기능을 추가했는데 첫번째는 document.activeElement인데 이 프로퍼티는 항상 현재 포커스를 가진 DOM 요소를 가리키는 포인터를 포함한다. 요소는 사용자 입력(일반적으로 탭 키)을 통해 받거나 focus() 메서드로 자동으로 포커스를 받는다.

var button = document.getElementById("myButton");
button.focus();
alert(document.activeElement === button);    // true
alert(document.hasFocus()); //true

 

문서를 처음 불러올 떄 document.activeEment는 기본적으로 document.body를 가리키며 문서를 완전히 불러오기 전에는 null이다. document.hasFocus()는 문서에 포커스가 있는지 나타내는 불리언 값을 반환한다.


11.3.3 HTMLDocument의 변화

readyState 프로퍼티
document 객체에서 readyState 프로퍼티를 처음 구현한 브라우저는 인터넷 익스플로러 4였고 HTML5에서 표준화 되었다. document의 readyState 프로퍼티에 가능한 값은 두 가지이다.

loading - 문서를 불러오는 중
complete - 문서를 완전히 불러옴

document.readyState 프로퍼티는 문서를 불러왔는지 확인하는 것으로 이전에는 onload 이벤트 핸들러를 써야했다. 

if(document.readyState == "complate"){
 
}

 

호환성 모드
선택 렌더링 방법을 도입함에 따라 브라우저에서 페이지를 어떤 모드로 렌더링 중인지 알아보기 위해 인터넷 익스플로러에서는 document에 compatMode라는 프로퍼티를 추가했는데 이 프로퍼티에는 브라우저의 렌더링 모드를 나타내는 역할만 있다. 표준모드는 document.compatMade는 "CSS1Compat"이며 쿽스모드는 document.compatMode는 "BackCompat"이다.


<head> 프로퍼티
HTML5에서는 각각 문서의 <head> 요소와 <body> 요소를 가리키는 document.head, documnet.body 프로퍼티를 도입했다.  

var head =  document.head || document.getElementsByTagName("head")[0]; 

이 코드는 document.head 프로퍼티가 존재하면 해당 프로퍼티를 사용하고 그렇지 않다면 getElementsByTagName() 메서드를 사용한다. 이 프로퍼티를 구현한 브라우저는 크롬과 사파리5이다.


11.3.4 문자셋 프로퍼티
HTML5에서 charset 프로퍼티는 문서의 문자셋을 나타내며 새 문자셋 지정도 가능하다.
defaultCharset 프로퍼티는 브라우저 및 시스템의 기본 설정에 따라 문서에 기본적으로 적용해야 할 문자셋을 나타내는데 이들 프로퍼티는 문서의 문자 인코딩에 대해 여러 가지를 알려주며 이를 컨트롤 할수 있게 한다.
document.charset 프로퍼티는 인터넷 익스플로러와 파이어폭스, 사파리, 오페라, 크롬에서 지원하고 document.defaultCharset 프로퍼티는 인터넷 익스플로러와 사파리, 크롬에서 지원한다.


11.3.5 커스텀 데이터 속성
HTML5 요소에서는 요소의 렌더링에 필요한 정보나 시맨틱 값이 아닌 데이터를 접두사 data-가 붙은 비표준 속성에 제공하도록 한다. 커스텀 데이터 속성을 정의하면 요소의 datasete 프로퍼티를 통해 접근할 수 있다. dataset 프로퍼티는 이름-값 쌍으로 이루어진 DOMStringMap 인스턴스인데 속성이름에서 data- 접두사를 제거한 프로퍼티로 표현된다.


11.3.6 마크업 삽입
DOM 노드를 연달아 만들고 이들을 순서대로 배열하는데 시간을 들이기보다 HTML 문자열로 만들어 삽입하는 편이 훨씬 쉽고 빠르기 때문에 HTML5에서 표준화 되었다.

innerHTML 프로퍼티
innerHTML을 읽기 모드로 사용하면 요소와 주석, 텍스트 노드 등의 자식 노드를 모두 나타내는 HTML 표현을 반환하고 쓰기 모드로 사용하면 주어진 값을 바탕으로 새 DOM 서브트리를 만들어 요소의 자식 노드를 완전히 교체한다.
인터넷 익스플로러와 오페라는 모든 태그를 대문자로 반환하며 사파리와 크롬, 파이어폭스는 공백과 들여쓰기를 포함해 HTML을 문서 그대로 반환한다. innerHTML을 쓰기 모드로 사용하면 주어진 문자열을 DOM 서브트리로 파싱해 이미 존재하는 자식 노드를 모두 교체한다. 주어진 문자열은 HTML로 간주되므로 태그는 모두 브라우저에서 HTML을 처리하는 표준에 따라 요소로 변환된다.

※ innerHTML을 설정하면 브라우저에서 HTML 문자열을 적절한 DOM 트리로 파싱한다. 즉 innerHTML을 설정하고 다시 읽으면 일반적으로 제공한 것과는 다른 문자열이 반환된다. 이는 원래 제공한 HTML 문자열로 DOM 서브트리를 생성한 다음 다시 직렬화한 결과 문자열을 반환하기 때문이다.

<script> 요소에 defer 속성이 있어야 하며 마이크로소프트에서 '스코프 요소'라고 부르는 요소 뒤에 있어야 하는데 인터넷 익스플로러는 innerHTML로 삽입하는 문자열 처음 부분에서 스코프 없는 요소를 모두 제거하므로 innerHTML로 삽입된 <script> 요소는  대부분의 브라우저에서 실행되지 않는다. 이 스크립트가 적절히 동작하게 하려면 닫는 태그 없는 <input> 같은 요소나 텍스트 노드 같은 스코프 요소 뒤에 써야 한다. <col>,<colgroup>,<frameset>,<head>,<html>,<style>,<table>,<tbody>,<thead>,<tfoot>,<tr>은 innerHTML을 지원하지 않는다.


outerHTML 프로퍼티
outerHTML을 읽기 모드에서 호출하면 호출한 HTML 요소를 자식 노드와 함께 반환하고 쓰기 모드에서 outerHTML을 호출하면 주어진 HTML 문자열을 파싱하여 DOM 서브트리를 생성하고 호출한 노드 전체를 교체한다.


insertAdjacentHTML() 메서드
이 베서드는 삽입할 뒤치와 HTML 텍스트 두 가지를 매개변수로 받는데 첫 번째 매개변수는 반드시 다음 값 중 하나여야 한다.

"beforebegin" - 호출한 요소 바로 앞에 삽입한다.
"afterbegin" - 호출한 요소의 첫 번재 자식 요소 바로 앞에 삽입한다.
"beforeend" - 호출한 요소의 마지막 자식 요소 바로 다음에 삽입한다.
"afterend" - 호출한 요소 바로 다음에 삽입한다.

값은 대소문자를 구분하지 않고 두번째 매개변수는 innerHTML/outerHTML과 마찬가지로 HTML문자열로 파싱되며 값을 제대로 파싱할 수 없다면 에러가 발생한다.


메모리와 성능 문제
이 섹션에서 설명한 메서드로 자식 노드를 교체하면 메모리 문제가 생길 수 있는데 인터넷 익스플로러에서 특히 심하다. 요소에 이벤트 핸들러가 등록돼 있거나 프로퍼티에 자바스크립트 객체가 있는 상태에서 해당 핸들러나 프로퍼티를 사용하여 요소를 문서 트리에서 제거한다면 요소와 이벤트 핸들러 사이의 연결이 메모리에 남기 때문에 innerHTML과 outerHTML, insertAdjacentHTML()을 사용할 때는 제거할 요소의 이벤트 핸들러나 자바스크립트 객체 프로퍼티를 모두 제거하길 권한다.

 


11.3.7 scrollIntoView() 메서드
브라우저들이 페이지 영역에서 스크롤을 구현하는 방법이 제각기 달랐기 때문에 HTML5 명세에 scrollIntoView()이 포함되었다. scrollIntoView() 메서드는 모든 HTML 요소에 존재하며 브라우저 창이나 커너테이너 요소를 스크롤해서 해당 요소가 뷰포트에 보이게 한다. 매개변수로 true를 넘기거나 생략하면 창 전체를 스크롤하여 요소 상단과 뷰포트 상단을 맞추고 그렇지 않다면 요소를 스크롤하여 뷰포트에서 완전히 보이게 하지만 상단을 맞추지는 않는다.

 


11.4 전용 확장

11.4.1 문서 모드
인터넷 익스플로러8은 '문서 모드'라는 새 개념을 도입했다. 문서 모드에 따라 지원하는 기능이 다르다.

internet Explorer 5 - 페이지를 쿽스 모드(인터넷 익스플로러 5의 기본 모드)로 렌더링한다. 익스플로러 8 이상의 새 기능은 지원하지 않는다.
internet Explorer 7 - 페이지를 익스플로러 7 표준 모드로 렌더링한다. 익스플로러 8 이상의 새 기능은 지원하지 않는다.
internet Explorer 8 - 페이지를 익스플로러 8 표준 모드로 렌더링한다. 선택자 API와 CSS2 선택자, CSS3 기능 일부, HTML5 기능 일부를 사용할 수 있다.
internet Explorer 9 - 페이지를 익스플로러 9 표준 모드로 렌더링한다. ECMAScript 5, 완전한 CSS3 지원, HTML5 기능 일부를 지원한다.

HTTP 헤더의 X-UA-Compatible이나 <meta> 태그로 특정 문서 모드를 강제할 수 있다.

<meta http-equiv="X-UA-Compatible" content="IE=EIVertion"> 
Edge - 문서를 항상 최신 문서 모드로 렌더링, 독타입은 무시한다.
EmulateIE9 - 독타입이 존재하면 문서 모드를 익스플로러 9 표준으로 맞추고 그렇지 않다면 5에 맞춘다.
9 - 문서 모드를 익스플로러 9 표준으로 강제, 독타입은 무시한다.

브라우저는 독타입을 보고 렌더링 모드를 판단하므로 X-UA-Compatible 필드를 반드시 써야 하는것은 아니다. 페이지에 적용된 문서 모드는 document.documentMode 프로퍼티를 통해 확인 가능하다.


11.4.2 children 프로퍼티
인터넷 익스플로러 9 미만 버전과 타 브라우저 사이에는 공백을 텍스트 노드로 취급하는 방법이 다르며 이 차이 때문에 children 프로퍼티가 만들어졌다. children 프로퍼티는 요소의 자식 요소만  포함하는 HTMLCollection이다.


11.4.3 contains() 메서드
contains() 메서드를 사용하면 문서 트리를 순회하지 않고도 주어진 노드가 다른 노드의 자손인지 확인이 가능하다. 이 메서드는 검색을 시작할 조상 노드에서 호출하며 확인해야할 노드를 매개변수로 받는다. 노드 사이의 관계는 DOM 레벨 3 메서드인 compareDocumentPosition()을 통해서도 확인이 가능하다.


11.4.4 마크업 삽입
innerText 프로퍼티
innerText를 읽기 모드로 사용하면 서브트리 순서대로 테스트 노드를 모두 결합한 값을 반환하고 쓰기 모드로 사용하면 자식 요소를 전부 제거한 다음 주어진 값으로 텍스트 노드를 만들어 삽입한다. innerText 값을 설정하면 자식 노드 전체를 제거하여 텍스트 노드 하나만 남으므로 태그 형태의 문자열도 모두 HTML 인코딩하여 텍스트 노드로 만든다.  파이어폭스는 innerText를 지원하지 않지만 textContent라는 프로퍼티를 지원한다.

※ innerText가 반환하는 콘텐츠는 인라인 스타일과 스크립트 블록을 생략하지만 textContent가 반환하는 콘텐츠는 인라인 스타일과 스크립트 코드도 반환한다. 브라우저 사이의 차이를 피하려면 깊이 중첩되지 않은 DOM 서브트리나 인라인 스타일 또는 인라인 스크립트가 존재하지 않는 부분의 텍스트만 읽어야 한다.


outerText 프로퍼티
outerText 프로퍼티는 호출한 노드에도 적용된다는 점을 제외하면 innerText와 똑같이 동작한다. 읽기 모드에서는 outerText와 innerText 사이에 차이가 없지만 쓰기 모드에서 outerText는 호출한 요소의 자식 노드만 교체하는 것이 아니라 자식 노드를 포함한 전체 요소를 교체한다.


11.4.5 스크롤
모든 요소에서 HTMLElement 타입의 확장 형태

scrollIntoViewIfNeeded(alignCenter) - 호출한 요소가 뷰포트에서 보이지 않을 경우 브라우저 창 또는 컨테이너 요소를 스크롤해서 요소가 뷰포트에 보이게 한다. 사파리와 크롬에서는 alignCenter 매개변수를 옵션으로 true를 넘기면 요소의 중앙 배치를 시도한다.
scrollByLines(lineCount) - lineCount에 주어진 숫자의 텍스트 줄 높이만큼 요소를 스크롤한다.
scrollByPages(pageCount) - pageCount에 주어진 숫자의 페이지 높이만큼 요소를 스크롤한다.

scrollIntoView()와 scrollIntoViewIfNeeded()는 요소의 컨테이너에서 동닥하고 scrollByLines()와 scrollByPages()는 요소 자체에서 동작한다.

모든 브라우저에서 지원하는 메서드는 scrollIntoView() 하나뿐이므로 일반적으로 이 메서드만 사용한다.

 

 

 

'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

14장 폼스크립트  (0) 2015.03.18
이벤트  (0) 2015.01.07
DOM  (0) 2014.12.08
클라이언트 감지  (0) 2014.11.20
브라우저 객체모델  (0) 2014.11.12

DOM

2014. 12. 8. 15:03 나홀로스터디/JS For Web Dev


10장 DOM

이 포스팅은 "프론트엔드 개발자를 위한 자바스크립트(2013 인사이트, 한선용 옮김)"에서 발췌 요약한 것입니다.
 
- DOM을 노드의 계층 구조로 이해
- 다양한 노드타입
- 브라우저들 간의 비호환성을 우회하는 DOM 코딩



문서 객체 모델 DOM은 HTML과 XML 문서에 대한 애플리케이션 프로그래밍 인터페이스(API)다. 넷스케이프와 마이크로소프트에서 초기에 사용하던 동적 HTML을 계승한 DOM은 이제 진정으로 플랫폼과 언어에 독립적인 페이지 표현 및 조작 방법이 되었다.

DOM 레벨 1은 1998년 10월에 W3C 권고가 되었고 기본적인 문서구조와 쿼리 인터페이스를 제공한다.

※ 인터넷 익스플로러8 및 이전 버전에서는 DOM 객체를 COM 객체로 구현했다. 따라서 이들 객체는 네이티브 자바스크립트 객체와는 다른 방식으로 동작한다.

 

10.1 노드의 계층 구조
HTML과 XML 문서는 모두 DOM을 통해 노드의 계층 구조로 표현 가능하다. 노드 타입에는 여러가지가 있으며 각 노트 타입은 서로 다른 특징, 데이터, 메서드를 가지고 각 노드는 다른 노드와 관계가 있을 수도 있다. 이런 계층 구조를 생성하며 특정 노드에 뿌리(root)를 둔 트리 구조로 표현된다.

문서 요소는 문서의 최상위 요소로 문서 하나에 문서 요소 하나만 존재하며 다른 요소는 모두 이 안에 존재한다. HTML 페이지에서 문서 요소는 항상 <html> 요소이고 XML에서는 미리 지정된 문서 요소가 없으면 어떤 요소든 문서 요소가 될 수 있다.


10.1.1  Node 타입
Node 인터페이스는 자바스크립트에서 Node 타입으로 구현되며 인터넷 익스플로러를 제외한 모든 브라우저에서 Node 타입에 접근할 수 있다. 자바스크립트의 노드 타입은 모두 Node를 상속하므로 모든 노드 타입에서 같은 기본 프로퍼티와 메서드를 공유한다.
모든 노드에는 타입을 나타내는 nodeType 프로퍼티가 있고 노드 타입은 다음 12가지 숫자형 상수 중 하나이다

Node.ELEMENT_NODE(1)
Node.ARRTIBUTE_NODE(2)
Node.TEXT_NODE(3)
Node.CDATA_SECTION_NODE(4)
Node.ENTITY_REFERENCE_NODE(5)
Node.ENTITY_NODE(6)
Node.PROCESSING_INSTRUCTION_NODE(7)
Node.COMMENT_NODE(8)
Node.DOCUMENT_NODE(9)
Node.DOCUMENT_TYPE_NODE(10)
Node.DOCUMENT_FRANMENT_NODE(11)
Node.NOTATION_NODE(12)


nodeName, nodeValue 프로퍼티
nodeName과 nodeValue 프로퍼티는 해당 노드의 정보를 제공한다. 프로퍼티 값은 노드 타입에 따라 완전히 다르므로 이 값을 사용하기 전에 항상 노트 타입을 테스트하길 권장한다.

if (someNode.nodeType == 1){
  value = someNode.nodeName;  // 요소의 태그 이름
} 

노드가 요소라면 nodeName 값을 변수에 할당한다. 요소의 nodeName은 항상 요소의 태그 이름과 일치하며 nodeValue는 항상 null이다.

 

노드 사이의 관계
모든 노드는 다른 노드와 관계가 있다. 각 노드에는 childNodes 프로퍼티가 있는데 이 프로퍼티에는 NodeList가 저장된다. NodeList는 배열 비슷한 객체인데 노드를 순서 있는 목록으로 저장하여 위치 기반으로 접근할 수 있다. NodeList에 length 프로퍼티가 있고 저장된 데이터를 대괄호 표기법으로 접근할 수 있긴 하지만 NodeList는 Array의 인스턴스가 아니다. NodeList 객체는 사실 DOM 구조에 대한 쿼리 결과이며 문서가 바뀌면 NodeList 객체에도 자동으로 반영되어 '살아있는' 객체라고 부르기도 한다.

각 노드에는 문서 트리에서 부모를 가리키는 parentNode 프로퍼티가 있고 childNodes 목록의 각 노드는 형제 관계이다. 같은 목록에 있는 노드 사이를 previousSiblingnextSibling 프로퍼티로 이동할 수 있다. 그 외에 편리한 메서드로 hasChildNodes()가 있는데 이 메서드는 노드에 자식 노드가 있다면 true를 반환하며 매번 childNodes 목록에서 length를 호출하는 것보다 효과적이다.
ownerDocument 프로퍼티는 전체 문서를 표현하는 문서 노드에 대한 포인터이다.

※ 노트 타입이 모두 Node를 상속하긴 하지만 노드 타입이 모두 자식 노드를 가질 수 있는 건 아니다.


노드조작
노드 사이의 관계 포인터는 모두 읽기 전용이므로 노드를 조작하는 메서드는 따로 있다. 가장 자주 쓰이는 메서드는 appendChild()인데 이 메서드는 childNodes 목록에 노드를 추가하고 새로 추가한 노드, 부모 노드, childNodes 목록에 포함된 모든 관계 포인터가 업데이트 되면 appendChild()는 새로 추가한 노드를 반환한다.

한 노드를 childNodes 목록 마지막이 아니라 특정 위치로 옮겨야 할 때insertBefore() 메서드를 사용한다. insertBefore() 메서드는 삽입할 노드기준 노드 두 가지를 매개변수로 받는데 삽입한 노드는 기준 노드의 이전 형제가 되며 이동이 끝나면 메서드는 삽입한 노드를 반환한다. 기준 노드가 null 이라면 insertBefore()는 appendChild()와 똑같이 동작한다.

appendChild()와 insertBefore()는 모두 기존의 노드를 제거하는 일 없이 삽입하기만 하는 반면 replaceChild() 메서드는 기존 노드를 교체한다.  replaceChild() 메서드는 매개변수로 삽입할 노드(A)와 교체할 노드(B) 두 개를 받아서 B를 문서 트리에서 제거해 반환하며 B가 있던 자리에 A를 대신 삽입한다. replaceChild()로 노드를 삽입하면 B의 관계 포인터를 모두 A에 복사한다.

노드를 제거할 때removeChild() 메서드를 사용한다. 이 메서드는 제거할 노드 하나만 매개변수로 받는데 제거된 노드는 함수 값으로 반환된다.

이들 네가지 메서드는 모두 특정 노드의 자식에서만 동작하므로 parentNode 프로퍼티에 해당하는 부모 노드를 정확히 알아야 한다.

 

기타 메서드
cloneNode() 메서드는 자신을 호출한 노드의 복제본을 생성한다. cloneNode() 메서드는 매개변수를 하나 받는데 이는 자손 노드까지 복제할지 나타내는 불리언으로 true를 넘기면 자손 노드 전체를 복제하며 false를 넘기면 해당 노드 하나만 복제한다.복제된 노드는 appendChild()나 insertBefore(), replaceChild()를 통해 문서에 추가하기 전에는 트리 안에 존재하지 않는다.

※ cloneNode() 메서드는 이벤트 핸들러처럼 DOM 노드에 추가한 자바스크립트 프로퍼티는 복사하지 않는다. 이 메서드는 속성과 자식 노드만 복사하며 다른 것은 모두 사라진다. 인터넷 익스플로러에는 이벤트 핸들러까지 복제하는 버그가 있으므로 복제하기 전에 이벤트 핸들러를 모두 제거하길 권한다.


 

10.1.2 Document 타입
자바스크립트는 문서 노드를 Document 타입으로 표현한다. 브라우저에서 전체 HTML 페이지를 표현하는 문서 객체는 HTMLDocument의 인스턴스이며 HTMLDocument는 Document를 상속한다. document 객체는 window의 프로퍼티이므로 전역에서 접근할 수 있다.  Document 노드에는 다음 특징이 있다.

- nodeType은 9이다.
- nodeName은 "#document"이다.
- nodeValue는 null이다
- parentNode는 null이다
- ownerDocument는 null이다
- 자식 노드로 DocumentType(최대 1개) Element(최대 1개), Processing Instruction, Comment를 가질 수 있다.


Document 타입은 HTML 페이지 또는 XML 기반 문서를 표현하며 가장 자주 쓰이는 용도는 document 객체를 통한 HTMLDocument의 인스턴스이다.

※  파이어폭스와 사파리, 크롬, 오페라에서는 스크립트에서 Document 타입 생성자 및 프로토타입에 접근할 수 있다. 인터넷 익스플로러는 버전 9에서도 Document를 노출하지 않는다. HTMLDocument 타입 생성자 및 프로토타입은 인터넷 익스플로러 버전 8 이후 및 기타 브라우저에서 접근할 수 있다.



Document의 자식 노드
DOM 명세에서는 Document 노드가 자식으로 DocumentType, Element, ProcessingInstruction, Comment를 가질 수 있다고 명시하는데 그중 두 가지 자식 노드에는 단축 표기도 있다. 첫 번째는 documentElement 프로퍼티인데 이는 항상 HTML 페이지의 <html> 요소를 가리킨다.  childNodes 목록에는 항상 document 요소가 있지만 documentElement 프로퍼티는 해당 요소에 더 빨리 더 직접적으로 접근한다.

document 객체는 HTMLDocument 의 인스턴스이므로 <body> 요소를 직접적으로 가리키는 body 프로퍼티를 갖는다. 주요 브라우저는 모두 document.documentElementdocument.body를 둘 다 지원한다. Document가 가질 수 있는 또다른 자식 노드는 DocumentType이다. <!DOCTYPE> 태그는 문서의 다른 부분과는 별도의 엔티티로 간주하며 포함된 정보는 doctype 프로퍼티(브라우저에서는 document.doctype)를 통해 접근할 수 있지만 브라우저마다 document.doctype을 달리 지원하므로 유용하게 쓰기 어렵다.
<html> 요소 밖에 있는 주석은 기술적으로는 문서의 자식 노드이지만 브라우저마다 다르게 처리한다.


문서정보
document 객체는 HTMLDocument의 인스턴스이므로 표준 Document 객체에는 현재 불러드린 웹 페이지에 대한 프로퍼티를 갖는다. title 프로퍼티는 브라우저 창 또는 탭의 제목인 <title> 요소 텍스트가 들어 있다. 이 프로퍼티로 현재 페이지 제목을 읽을 수 있고 설정도 가능한데 title 프로퍼티의 값을 바꿔도 <title> 요소는 변함이 없다.


요소 위치
DOM 관련해서 가장 자주 하는 일은 특정 요소나 요소 그룹에 대한 참조를 얻는 일인데 document 객체에는 getElementById()getElementsByTagName() 두가지 메서드를 제공한다. getElementById() 메서드는 찾으려는 요소 ID를 매개변수로 받고 해당 요소를 찾아 반환하며 그런 ID 요소가 존재하지 않으면 null을 반환한다.
getElementByTagName() 메서드는 요소의 태그 이름을 매개변수로 받고 해당하는 요소가 담긴 NodeList를 반환한다.

var images = document.getElementByTagName("img"); 

HTMLCollection 객체는 images 변수에 저장되고 객체에 담긴 요소 숫자는 length 프로퍼티에 저장된다. HTMLCollection 객체에는 namedItem() 메서드도 있는데 이 메서드는 name 속성을 통해 컬렉션 데이터에 대한 참조를 얻는다. HTMLCollection 객체에서는 대괄호 표기법에 숫자형 색인과 문자형 색인을 모두 쓸수 있는데 숫자형 색인을 쓰면 이면에서 item()을 호출하고 문자열 색인을 쓰면 namedItem()을 호출한다.

※ 명세에서는 태그 이름이 대소문자를 구분하는 것으로 정의되어 있지만 getElementByTagName() 메서드는 기존의 HTML 페이지와 최대한 호환되게 하기 위해 대소문자를 구분하지 않는다. XHTML이나 XML페이지에서는 getElementByTagName() 메서드가 대소문자를 구분한다.

세번째 메서드는 HTMLDocument 타입에만 정의된 getElementByName()으로 name 속성 값이 주어진 문자열에 일치하는 요소를 반환한다. getElementByTagName()와 마찬가지로 getElementByName() 메서드 역시 HTMLCollection을 반환한다. name() 메서드는 항상 첫 번째 버튼만 가져오는데 name 속성이 모두 같기 때문이다.


특별한 컬렉션

document.anchors - name 속성이 있는 <a> 요소를 모두 가져온다
document.form - <form> 요소를 모두 가져온다. document.getElementsByTagName("form")과 같다
document.images - <img> 요소를 모두 가져온다. document.getElementsByTagName("img")와 같다.
document.links - href 속성이 있는 <a> 요소를 모두 가져온다.



문서에 쓰기
웹페이지에 출력을 직접 조작하는 기능을 담당하는 메서드는 write(). writeIn(), open(), close() 네 가지다. write(), writeIn() 메서드는 문자열을 매개변수로 받는데 write()는 넘겨 받은 텍스트를 그대로 추가하고, writeIn()은 줄바꿈 문자(\n)를 마지막에 추가한다.

※ XHTML 문서에서는 문서에 쓰는 기능을 지원하지 않는다. application/xml_xhtml 마임 타입으로 전송되는 페이지에서는 이 메서드가 동작하지 않는다.

 


10.1.3 Element 타입
Element 타입은 XML/HTML 요소를 표현하며 이를 통해 태그 이름이나 자식, 속성 같은 정보에 접근 가능하다.

nodeType은 1이다.
nodeName은 요소의 태그 이름이다.
nodeValue는 null이다.
parentNode는 Document 또는 Element이다.
자식 노드로 Element나 Text, Comment, ProcessingInstruction, CDATA Section, EntityRefernce를 가질수 있다.

요소의 태그 이름은 nodeName 프로퍼티나 tagName 프로퍼티로 얻을수 있고 두 프로퍼티는 같은 값을 반환하는데 후자가 더 직관적이다.
HTML에서 tagName을 사용하면 태그 이름은 항상 대문자로 반환되므로 element.tagName.toLowerCase()를 사용하는 것이 안전하다

※ Element 타입 생성자와 프로토타입은 인터넷 익스플로러 버전 8을 포함해 모든 최신 브라우저에서 스크립트를 통해 접근할 수 있다. 사파리 버전2 미만이나 오페라 버전 8미만 같은 오래된 브라우저는 Element 타입 생성자를 스크립트에 노출하지 않는다.


HTML 요소
HTML요소는 모두 HTMLElement 타입을 통해 표현된다. HTMLElement는 Element를 직접적으로 상속하며 몇가지 프로퍼티가 추가되는데 각 프로퍼티는 모든 HTML 요소에서 사용가능한 표준 속성중 하나를 나타낸다.

id - 요소의 고유한 식별자
title - 요소에 대한 추가 정보, 일반적으로 툴팁으로 표현된다.
lang -  요소 콘텐츠의 언어 코드
dir - 언어의 표기 방향
className -  요소의 CSS 클래스인 class 속성을 나타냄, class가 ECMAScript의 예약어이기 때문에 class라고 부르지 못함

각 프로퍼티는 속성 값을 읽는 용도로도, 값을 설정하는 용도로도 사용한다.


속성얻기
속성에 대한 DOM 메서드는 getAttribute(), setAttribute(), removeAttribute() 이다.
getAttribute()에는 속성 이름을 그대로 써야 하고 주어진 속성이 존재하지 않으면 항상 null을 반환한다. getAttribute() 메서드는 HTML 언어에 공식적으로 포함되지 않는 커스텀 속성의 값을 가져오는 데도 쓸 수 있다.
요소 속성은 모두 DOM 요소 객체의 프로퍼티를 통해서도 접근할 수 있다. HTMLElement에 정의된 다섯 가지 프로퍼티는 해당 속성과 직접 연결되며, 그 외에도 브라우저에서 인식하는(커스텀이 아닌) 속성은 모두 객체 프로퍼티로 추가된다.

두번째 속성은 onclick 같은 이벤트 핸들러 속성인데 요소의 onclick 속성은 자바스크립트 코드이며 getAttribute()는 해당 코드 문자열을 반환한다. 반면 onclick 프로퍼티는 이벤트 처리 프로퍼티가 자신에게 할당된 함수에 접근할 수 있기 때문에 자바스크립트 함수를 반환하고 해당 속성이 없을 때는 null을 반환한다.
이런 차이로 개발자들은 DOM을 다룰 때 객체 프로퍼티를 사용하고 getAttribute() 메서드는 주로 커스텀 속성의 값을 가져올 때 사용한다.


속성 설정
getAttribute()의 형제 메서드인 setAttribute()는 속성 이름과 설정할 값 두 가지를 매개변수로 받는다. 속성이 존재하면 setAttribute()는 해당 속성의 값을 교체하며 존재하지 않을 때는 속성을 새로 생성하고 값을 설정한다. setAttribute() 메서드는 HTML 속성과 커스텀 속성을 같은 방식으로 다룬다. 속성은 모두 프로퍼티이므로 프로퍼티에 직접 할당하는 것은 속성 값을 설정하는것과 마찬가지다.
커스텀 프로퍼티를 추가하면 대부분의 브라우저에서 요소 속성이 되지 않지만 인터넷 익스플로러에서는 가능하다.

※ 인터넷 익스플로러 7 및 이전 버전에서는 setAttribute()가 좀 이상하게 동작한다. class나 style속성을 설정해도 효과가 없으며 setAttribute()로 이벤트 핸들로 프로퍼티를 설정하려 해도 아무 효과가 없다. 이 문제가 인터넷 익스플로러8에서 고쳐지긴 했지만 이들 속성을 설정할 때는 항상 프로퍼티를 이요하는 편이 좋다.


removeAttribute() 메서드는 속성의 값만 지우는 것이 아니라 요소에서 속성을 완전히 제거한다.

※ 인터넷 익스플로러 6 이전버전은 지원하지 않는다.

 

attributes 프로퍼티
Element 타입은 DOM 노드 타입 중에서 attribute 프로퍼티를 갖는 유일한 타입이다. attribute 프로퍼티에는 "살아있는" 컬렉션(NodeList와 비슷한) NamedNodeMap이 저장된다. 요소의 속성은 모두 Attr 노드로 표현되며 각 Attr 노드는 NameNodeMap객체에 저장된다.

getNamedItem(name) - nodeName 프로퍼티가 name인 노드를 반환한다.
removeNamedItem(name) - nodeName 프로퍼티가 name인 노드를 목록에서 제거한다.
setNamedItem(node) - node를 목록에 추가하고 nodeName 프로퍼티에 따라 색인한다
item(pos) - 인덱스가 pos인 노드를 반환한다.

attributes 프로퍼티 안의 각 노드는 nodeName이 속성 이름이며 nodeValue는 속성 값이다.

element.attributes.getNamedItem("id").nodeValue
element.attributes["id"].nodeValue; 

removeNamedItem() 메서드는 요소의 removeAttribute() 메서드와 마찬가지로 주어진 이름의 속성을 제거한다.
setNamedItem() 메서드는 속성 노드를 넘겨 요소에 새 속성을 추가하는 메서드인데 속성 메서드보다는 getAttribute(). removeAttribute(), setAttribute() 메서드가 더 많이 쓰인다.


요소 생성
document.ceateElement() 메서드를 통해 새 요소를 생성할 수 있다. 이 메서드는 생성할 요소의 태그 이름 하나만 매개변수로 받는다. createElement() 메서드는 새 요소를 생성하고 ownerDocument 프로퍼티를 설정한다.

인터넷 익스플로러7 및 이전 버전에서 동적으로 요소를 생성할 때 발생하는 문제점은 다음과 같다.

- 동적으로 생성한 <iframe> 요소의 name 속성을 설정할 수 없다.
- 동적으로 생성한 <input> 요소는 폼의 reset() 메서드로 리셋되지 않는다.
- 동적으로 생성한 <button> 요소에 타입 속성 "reset"이 있어도 이 버튼은 폼을 리셋하지 못한다.
- 동적으로 생성한 라디오 버튼은 같은 name 속성의 라디오 버튼과 연결되지 않는다.

인터넷 익스플로러7 및 이전 버전의 이런 문제는 createElement()에 완전한 HTML 태그를 넘겨서 해결 가능하다


요소의 자식
요소는 자식 요소나 자손 요소를 가질 수 있으며 그 숫자에는 제한이 없다. 특정 태그 이름의 자식 노드나 자손 요소를 가져올 때는 getElementByTagName() 메서드도 사용한다. 이 메서드를 요소에서 호출하면 document에서 호출한 것과 똑같이 동작하지만 해당 요소에서 검색을 시작한다는 점만 다르며 따라서 자손 요소만 반환한다.



10.1.4 Text 타입
Text 노드는 Text 타입으로 표현된다. 이 노드는 평범한 텍스트가 포함되고 글자 그대로 사용되며 이스케이프된 HTML 문자는 포함할 수 있지만 HTML 코드는 포함할 수 없다.

- nodeType은 3이다.
- nodeName은 "#text"이다.
- nodeValue는 노드에 포함된 텍스트이다
- parentNode는 Element 이다.
- 자식 노드를 가질 수 없다.

Text 노드에 포함된 텍스트는 nodeValue 프로퍼티나 data 프로퍼티로 가져올 수 있으며 두 프로퍼티에는 같은 값이 저장되고 nodeValue나 data 둘 중 하나를 바꾸면 노드에 반영된다.

- appendData(text) - 노드 마지막에 text를 추가한다.
- deleteData(offset, count) - offset부터 count 만큼 삭제한다.
- insetDate(offset, text) - offset 위치에 text를 삽입한다.
- replaceData(offset, count, text) - offset부터 (offset + count)까지의 텍스트를 text로 교체한다.
- splitText(offset) - offset 위치를 기준으로 텍스트 노드를 둘로 나눈다.
- substringData(offset, count) - offset 위치부터 (offset + count) 까지의 텍스트를 꺼낸다.

이들 메서드 외에도 length 프로퍼티도 지원되며 노드의 글자 개수를 반환한다. 이값은 nodeValue.length나 data.length와 같다.


텍스트 노드 생성
새 텍스트 노드를 생성할 때는 document.createTextNode() 메서드를 사용한다. 이 메서드는 매개변수로 삽입할 텍스트를 받는다. 새 텍스트 노드를 생성하면 ownerDocument 프로퍼티가 설정되지만 문서 트리에 삽입하기 전에는 브라우저 창에 표시되지 않는다. 텍스트 토드를 다른 텍스트 노드의 형제로 추가하면 두 텍스트 노드는 사이의 공백이 없는것으로 표시된다.


텍스트 노드 통일
형제 텍스트 노드를 하나로 합치는 메서드로 normalize()가 있고 Node 타입에 존재하므로 모든 노드에서 사용가능하다. 노드에서 normalize()를 호출하면 자식 노드를 텍스트 노드 하나로 병합하며 합쳐진 텍스트 노드의 nodeValue는 각 텍스트 노드의 nodeValue 프로퍼티를 하나로 합친 값과 같다.  브라우저가 문서를 파싱하면 형제 텍스트 노드는 생성되지 않고 DOM을 조작할 때만 생긴다.

※ 인터넷 익스플로러 6에서는 normalize() 메서드가 간혹 충돌한다. 확인할 수는 없었지만 이 문제는 패치를 통해 수정되었을수 있다.


텍스트 노드 분할
Text 타입에는 normalize() 의 반대 역할을 하는 splitText() 메서드가 있다. 이 메서드는 주어진 오프셋을 기준으로 텍스트 노드를 둘로 나눈다. 이 메서드가 반환하는 새 텍스트 노드의 parentNode는 원래 텍스트 노드의 parentNode와 같다. 텍스트 노드 분할은 텍스트 노드에서 데이터를 추출하는 DOM 파싱 테크닉에서 가장 자주 쓰인다.



10.1.5 Comment 타입
주석은 DOM에서 Comment 타입으로 표현된다.

- nodeType는 8이다.
- nodeName은 "#comment"이다.
- nodeValue는 주석 콘텐츠이다
- parentNode는 Document  또는 Element이다.
- 자식 노드는 가질 수 없다.

Commenet 타입은 Text 타입과 같은 원형을 상속하므로 Text 타입에 있는 문자열 메서드를 대부분 갖고 있는데 splitText()는 예외다. 또한 Text 타입과 마찬가지로 nodeValue나 data 프로퍼티로 주석의 콘텐츠를 가져올 수 있다.

※ Comment 타입 생성자와 프로토타입에 접근할 수 잇는 브라우저는 파이어폭스, 사파리, 크롬, 오페라다. 인터넷 익스플로러8은 태그 이름에 "!"가 들어가는 요소를 주석 노드로 간주한다. 즉 getElementsByTagName()이 주석 노드를 반환할 수 있다는 뜻이다. 인터넷 익스플로러 9에서는 커스텀 생성자 HTMLCommentElement가 주석을 나타낸다. 이 생성자에서 주석을 요소로 취급하는건 아니다.




10.1.6 CDATASection 타입
CDATA 섹션은 XML 기반 문서 전용이며 CDATASection 타입으로 표현된다. Comment와 마찬가지로 CDATASection 타입 역시 Text 타입과 같은 원형을 상속하므로 splitText()를 제외한 문자열 메서드를 모두 가진다. CDATASection 노드에는 다음 특징이 있다.

- nodeType은 4이다.
- nodeName은 "#cdata-section"이다.
- nodeValue는 CDATA 섹션의 콘텐츠이다.
- parentNode는 Document 또는 Element이다.
- 자식 노드는 가질 수 없다.

CDATA 섹션은 XML 문서에서만 유효하므로 대부분의 브라우저에서 CDATA 섹션을 부정확한 Comment 나 Element 로 잘못 파싱한다.

※ CDATASection  타입 생성자와 프로토타입에 접근할 수 잇는 브라우저는 파이어폭스와 사파리, 크롬, 오페라다. 인터넷 익스플로러는 버전 9까지 아직 이 타입을 지원하지 않는다.




10.1.7 DocumentType 타입
DocumentType 타입은 자주 쓰이지 않으며 이를 지원하는 웹 브라우저는 파이어폭스와 사파리, 오페라 뿐이다.

- nodeType은 10이다
- nodeName은 독타입 이름이다.
- nodeValue는 null이다.
- parentNode는 Document이다.
- 자식 노드는 가질 수 없다.




10.1.8 DocumentFragment 타입
DocumentFragment 타입은 마크업에 표현되지 않는 유일한 노드 타입이다. DOM에서는 문서 버퍼를 노드를 가지며 조작할 수 있을 뿐이고 그 외 복잡한 기능은 전부 제거된 "경량화된" 문서로 정의한다.

- nodeType은 11이다.
- nodeName은 "#document-fragment"이다.
- nodeValue는 null이다.
- parentNode는 null이다.
- 자식노드로 Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference를 가질수 있다.

문서 버퍼는 document.createDocumentFragment() 메서드로 생성하고 콘텐츠는 appendChild(), insetBefore()로 문서에 추가한다.



10.1.9 Attr 타입
요소의 속성은 DOM에서 Attr 타입으로 표현된다. Attr 타입 생성자와 프로토타입에 접근할 수 있는 브라우저는 인터넷 익스플로러 버전 8 이후 브라우저이고 기술적으로 속성은 요소의 attributes 프로퍼티 안에 존재하는 노드이다.

- nodeType은 11이다.
- nodeName은 속성이름이다.
- nodeValud는 속성 값이다.
- parentNode는 null이다.
- HTML에서는 자식노드를 가질 수 없다.
- XML에서는 자식 노드로 Text, EntityReference를 가질 수 있다.

Attribute 노드를 직접 참조하는 경우는 드물며 개발자들은 보통 getAttribute(), setAttribute(), removeAttribute()를 더 선호한다.
Attr 객체에는 세 가지 프로퍼티가 있는데 name은 속성 이름이며 nodeName과 같다. value는 속성 값이고 nodeValue와 같다. specified는 해당 속성이 코드에 명시되었는지 기본 값인지 나타내는 불리언이다.
새 attribute 노드를 생성할 때는  document.createAttribute()에 속성 이름을 넘겨 호출한다.

 


10.2 DOM 다루기

10.2.1 동적 스크립트
동적 스크립트에는 외부 파일을 불러오거나 텍스트를 직접 삽입하는 두 가지 방법이 있다. 동적으로 외부 파일을 불러오는 과정은 <scrtipt> 요소를 사용하는 것이고 직접 삽입하는 방법은 인라인 스크립트이다.


10.2.2 동적 스타일
css 스타일을 HTML 페이지에 삽입하는 요소는 두 가지이다. <link> 요소는 외부 CSS 파일을 불러올 때 사용하고 <style> 요소는 인라인 스타일에 사용한다. DOM 코드로 생성하는 link 요소가 제대로 동작하려면 body가 아니라 <head> 요소에 추가해야 한다.
스타일을 정의하는 다른 방법은 <style> 요소로 인라인 CSS 를 사용하는 것이 있는데 인터넷 익스플로러는 <style> 노드를 특별 취급하여 자식 노드에 대한 접근을 허용하지 않기 때문에 styleSheet를 써야한다. 이 프로퍼티에는 cssText라는 프로퍼티가 존재하며 이를 통해 css 코드를 설정할 수 있다.


10.2.3 테이블 조작
<table> 요소는 DOM 코어 메서드로 생성하기 어렵기 때문에 공식화할 수 있게끔 몇가지 프로퍼티와 메서드를 추가했다.

<table> 요소에 추가된 내용

- caption - <caption> 요소를 가리키는 포인터이다.
- tBodies - <tbody> 요소의 HTMLCollection이다.
- tBoot - <tfoot> 요소를 가리키는 포인터이다.
- tHead - <thead> 요소를 가리키는 포인터이다.
- rows - 테이블의 모든 행에 대한 HTMLCollection 이다.
- createThead() - <thead> 요소를 생성해 테이블에 삽입하고 그 참조를 반환한다.
- createTFoot() - <tfoot> 요소를 생성해 테이블에 삽입하고 그 참조를 반환한다.
- createCaption() - <caption> 요소를 생성해 테이블에 삽입하고 그 참조를 반환한다.
- deleteTHead() - <thead> 요소를 삭제한다.
- deleteTFoot() - <tfoot> 요소를 삭제한다.
- deleteCaption() - <caption> 요소를 삭제한다.
- deleteRow() - 주어진 위치의 행을 삭제한다.
- insertRow(pos) - rows 컬렉션에서 주어진 위치에 행을 삽입한다.


<tbody> 요소에 추가된 내용

- rows - <tbody> 요소에 포함된 행의 HTMLCollection이다.
- deleteRow(pos) - 주어진 위치의 행을 삭제한다.
- insertRow(pos) - rows 컬렉션에서 주어진 위치에 행을 삽입하고 그에 대한 참조를 반환한다.


<tr> 요소에 추가된 내용

- cells - <tr> 요소에 포함된 셀의 HTMLCollection이다.
- deleteCell(pos) - 주어진 위치의 셀을 삭제한다.
- insertCell(pos) - cells 컬렉션의 주어진 위치에 셀을 삽입하고 새 셀에 대한 참조를 반환한다.




10.2.4 노드리스트 사용
NodeList 객체와 이와 관련된 NamedNodeMap, HTMLCollection을 이해하면 DOM을 전체적으로 이해하는데 큰 도움이 된다. 문서 구조가 바뀔 때마다 컬렉션도 업데이트되므로 항상 정확한 정보를 반환한다는 뜻으로 NodeList 객체는 해당 객체에 접근할 때마다 수행되는 쿼리라고 말할수 있다.

 

 

 


 

'나홀로스터디 > JS For Web Dev' 카테고리의 다른 글

이벤트  (0) 2015.01.07
DOM 확장  (0) 2014.12.18
클라이언트 감지  (0) 2014.11.20
브라우저 객체모델  (0) 2014.11.12
함수 표현식  (0) 2014.10.23
Copyright © HuckleberryM All Rights Reserved | JB All In One Designed by CMSFactory.NET