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
Copyright © HuckleberryM All Rights Reserved | JB All In One Designed by CMSFactory.NET