웹 페이지의 내용을 js로 다룰때는 단순히 내용을 문자열로 다루는 것 보다 어떠한 덩어리로 조작하는 것이 더 쉽다. 이를 위한 것이 DOM이다.
DOM은 HTML, XML문서를 프로그램에서 이용하기 위한 API이며 트리 구조를 사용한다. 이때 이 트리를 DOM트리라 한다. 구조 자체가 트리인 만큼 DOM트리 안에서 각 객체를 노드라 하며 어떤 노드와 다른 노드와의 관계는 트리에서 사용하는 관계와 같다(부모, 자식 등).
DOM 사양은 W3C에 의해 Level1~3으로 정의되 있다.
DOM Level 1
DOM Level1은 Core, HTML이 두 가지 모듈로 구성되 있다.
모듈 | 설명 |
Core | HTML에 한정되지 않은 일반적인 DOM 조작에 대한 사양 getElementsByTagName - 태그명을 지정해 요소를 구한다 createElement - 요소를 작성한다 appendChild - 요소를 삽입한다 |
HTML | HTML 문서 특유의 메서드에 대한 사용 |
DOM Level 2
DOM Level2는 Level1의 모듈을 가지면서 이벤트 처리에 관한 Events 모듈이 들어 있다. CSS 또 한 여기에 정의되 있다. IE8이하는 Level2를 따르지 않고 파이어폭스, 크롬은 Level2를 거의 완벽하게 지원한다.
모듈 | 설명 |
Core | Level1 Core의 확장 |
HTML | Level1 HTML의 확장 |
Views | 문서의 표시 상태에 대한 사양 |
Events | 캡처링, 버블링, 이벤트 취고 등의 이벤트 시스템의 사양 |
Style | stylesheet에 대한 사양 |
Traversal and Range | DOM트리를 따라가는 방법이나 범위 지정에 대한 사양 |
DOM Level3
DOM Level3은 아직 권고 단계에 있지 않다. 하지만 최신 브라우저 에서는 Events 모듈에 정의된 내용이 구현되 있다.
모듈 | 설명 |
Core | Level2 Core의 확장 |
Load and Save | 문서 구조 읽고 쓰기에 대한 사양 |
Validation | 문서 구조가 타당한지를 검증하기 위한 사양 |
XPath | XPath에 대한 사양 |
Events | Level2 Events의 확장, 키보드 이벤트 지원 |
요소, 노드
요소와 노드는 상속 관계에 있고, 노드가 상위 타입이다. 노드에는 nodeType이라는 속성이 존재하는데 이 값이 ELEMENT_NODE(1)인것이 요소이다. 다음은 HTML문서에서 주로 사용되는 노드이다.
노드 | 노드 타입 상수 | 노드 타입의 값 | 인터페이스 |
요소 노드 | ELEMENT_NODE | 1 | Element |
속성 노드 | ATTRIBUTE_NODE | 2 | Attr |
텍스트 노드 | TEXT_NODE | 3 | Text |
코멘트 노드 | COMMENT_NODE | 8 | Comment |
문서 노드 | DOCUMENT_NODE | 9 | Document |
Document 객체
Document 객체는 DOM 트리에서 루트 노드 이다. Document객체는 documentElement property or body property에 대응하지만 특정 태그에 대응되지는 않는다. Document객체를 해당 HTML문서 전체를 표현한다.
Document객체는 js안에서 document 전역 변수로 접근할 수 있으며 document는 window 객체의 프로퍼티로 존재 한다. 하지만 window 객체는 전역 객체 이므로 해당 프로퍼티에 접근할 때에는 window를 생략해도 된다.
getElementsByTagName()
getElementsByTagName은 Document.getElemetById()와는 다르게 Document객체와 Element객체 양쪽의 메서드이다. getElementById()는 Document 객체에만 존재한다. 따라서 특정 Element 객체에 대해 getElementsByTagName()을 실행하면 해당 Element 객체의 자손 노드 가운데 특정 태그 명을 지닌 요소를 구한다.
라이브 객체(또는 Live Collection)
getElementsByTagName()을 사용 시 주의할 점이 있다. 이를 사용하면 NodeList객체가 구해 진다는 점이다. NodeList는 유사 배열, 즉 배열의 형태를 띄고 있지만 배열이 아닌 객체이다. 여기서 NodeList는 라이브 객체이며 라이브 객체는 DOM 트리에 대한 참조를 가지고 있기 때문에 DOM의 변경 사항을 실시간으로 반영 한다. Element.childNodes또한 라이브 객체를 반환 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<div id="foo">
<span>first</span>
<span>second</span>
</div>
<script>
const elems = document.getElementsByTagName('span');
console.log(elems.length);//2
const newSpan = document.createElement('span');
newSpan.appendChild(document.createTextNode('third'));
const foo = document.getElementById('foo');
foo.appendChild(newSpan);
console.log(elems.length);//3
</script>
|
cs |
라이브객체는 다음과 같이 반복문을 실행할 때 문제가 생긴다. 아래와 같이 코드를 작성하면 라이브 객체의 특성 때문에 무한루프를 돌게 된다.
1
2
3
4
5
6
7
|
const divs = document.getElementsByTagName('div');
let newDiv;
for(let i = 0; i < divs.length; i++) {
newDiv = document.createElement('div');
newDiv.appendChild(document.createTextNode('new div'));
divs[i].appendChild(newDiv);
}
|
cs |
라이브 객체의 성능
라이브 객체를 성능상으로 좋지 않다. 따라서 라이브 객체를 한번 slice()를 사용해 Array로 변환 후 사용하는 편이 성능상 뛰어 나다. 라이브 객체는 성능 면에서 문제가 있으므로 라이브러리에서는 Array로 변환하고 나서 반환하는 것도 있다
NodeList외에도 HTMLCollection은 라이브 객체이다. DOM Level 1에 정의되 있는 HTMLCollection은 다음과 같다.
HTMLCollection | 설명 |
document.images | 문서 안의 img 요소 목록 |
document.apples | 문서 안의 자바 애플릿 객체 목록 |
document.links | 문서 안의 링크 요소(<a href>)목록 |
document.forms | 문서 안의 form요소 목록 |
document.anchors | 문서 안의 앵커 요소 (a 태그 안에 name 속성이 설정되 있는거) 목록 |
form.elements | 폼 안에 input 요소 목록 |
map.areas | 이미지 맵 안의 area목록 |
table.rows | 테이블 안의 tr목록 |
table.tBodies | 테이블 안의 tbody목록 |
tableSection.rows | 테이블 세션(thead 요소, tfoot 요소)안의 tr 요소 목록 |
row.cells | 테이블의 행 안의 td요소와 th요소 목록 |