DOM

yeonhwan619·2022년 9월 13일

기록) JS 기초

목록 보기
5/10

DOM (Document Object Model)은 웹 페이지를 위한 API로, HTML을 파싱하여 객체 모델로 변환한 후, 이를 통해 웹 페이지와 상호작용 할 수 있게 한다.

DOM (Document Object Model)

웹페이지 도큐멘트(HTML)를 객체를 통한 트리 구조 형태의 모델로 해석하여 웹 페이지와 상호작용 할 수 있게 하는 API이자 인터페이스. 모던 웹 브라우저들이 자바스크립트를 기반으로 한 엔진을 사용하기 때문에 자바스크립트로 구현이 되어 있을 뿐 자바스크립트가 아닌 언어로도 DOM 모델을 사용해 웹페이지와 상호작용이 가능하다. (자바스크립트도 node.js 런타임의 개발로 인해 웹 외의 분야에서도 사용할 수 있다.)

DOM의 구조

DOM은 HTML문서를 파싱하여 다음 그림과 같은 트리 구조를 가진 객체모델을 형성한다.
각각의 HTML의 요소들은 트리를 구성하는 node로 변환되며, 각 노드들은 상속 구조(부모, 자식 관계)를 갖는다. DOM 트리구조의 최상단 노드에는 root node인 document 가 존재하며, 그 이후는 작성된 HTML 문서의 상속 구조를 따라 각 요소들이 노드로 변환되어 할당 된다. 각 요소 노드 들은 어트리뷰트노드, 텍스트노드를 가질 수 있으며 이들은 생략될 수도 있다. 텍스트노드의 경우 해당 요소 노드의 반드시 자식 노드이며 어트리뷰트노드는 부모요소를 갖지 않는 특징을 갖는다.

DOM의 상속

DOM은 웹페이지와 다양한 방법으로 상호작용하기 위해 다양한 프로퍼티와 메소드를 제공하는데, 이는 자바스크립트엔진에서 프로토타입체인을 통해 구현한다. 하나의 document는 다음과 같은 프로토타입 체인을 갖음으로써 DOM 인터페이스를 만든다.
1) Object 객체는 모든 객체들의 프로토타입으로 객체 조작의 기본적인 프로퍼티와 메소드를 제공하며, 2) EventTarget 객체는 노드요소가 웹페이지에서 발생하는 각종 이벤트들과 상호작용하기 위한 인터페이스를 제공하며, 3) Node 객체는 트리 자료구조를 순회하며 해당 노드와 관련된 요소를 탐색할 인터페이스를 제공하고, 4) Element, HtmlElement, Attr 또한 각 요소에 필요한 인터페이스들을 제공한다.

DOM 인터페이스

Node 요소의 취득

1) Document.prototype.getElementBy...

getElementBy.. 메소드를 사용하면 HTML요소에 해당하는 어트리뷰트, 태그내임등으로 DOM 트리에서 해당 요소를 지정하여 획득할 수 있다. getElementById 는 해당 id를 가진 노드 하나를 획득하며, TagName과 ClassName으로도 획득할 수 있다. 단, 해당 요소의 노드가 하나 이상일 경우 가장 처음에 탐색되는 노드를 반환한다. 복수의 요소 노드를 취득하고 싶을 경우 getElementsByTagName 처럼 복수형으로 사용가능하며 이때, 메소드는 모든 해당 요소 노드를 포함하고 있는 HTMLCollection 객체를 반환한다. (HTMLCollection 객체는 유사배열객체로 이터러블이다. 또한 HTMLCollection 객체는 객체의 상태가 실시간으로 변경될 수 있는 살아있는 객체이다.)

2) Document.prototype.querySelector

querySelector 메소드를 사용하면 HTMl요소에 부여된 CSS 선택자를 통해 해당 요소를 획득할 수 있다. querySelector는 해당 요소를 한 개만 획득할 수 있으며, 복수의 노드가 존재할 경우 제일 처음에 해당 되는 노드를 반환한다. 복수의 노드를 획득하고 싶을 경우 querySelectorAll 메소드를 사용한다. 이때, querySelectorAll은 NodeList 객체에 해당 노드들을 담아 반환한다. (NodeList 객체 또한 유사배열객체이며 이터러블이다. NodeList 객체는 HTMLCollection 객체와 다르게 실시간 반영 객체가 아니다. 그러나 childNodes 메소드를 통해 반환된 NodeList 객체의 경우 살아있는 객체가 된다.)


Node 요소의 탐색


노드의 탐색 메소드들은 다음 그림과 같이 존재한다. 노드의 탐색을 실시할 때에는 DOM트리 구조에 자동적으로 생성되는 공백텍스트 노드들의 존재유무에 주의해야 한다.

자식 노드 탐색

1) Node.prototype.childNodes
해당 노드의 자식노드들을 NodeList 객체에 담아 반환 (텍스트노드 포함)

2) Element.prototype.children
해당 노드의 자식노드들을 모두 HTMLCollection 객체에 담아 반환 (요소 노드만을 포함)

3) Node.prototype.firstChild
해당 노드의 첫번째 자식 노드를 반환 (텍스트/요소 노드)

4) Node.prototype.lastChild
해당 노드의 마지막 자식 노드를 반환 (텍스트/요소 노드)

5) Element.prototype.firstElementChild
해당 노드의 첫번째 자식 노드를 반환 (반드시 요소 노드)

6) Element.prototype.lastElementChild
해당 노드의 마지막 자식 노드를 반환 (반드시 요소 노드)

부모 노드 탐색

1) Node.prototype.parentNode
해당 노드의 부모 노드를 탐색한다.

형제 노드 탐색

1) Node.prototype.previousSibling
해당 노드의 형제 노드 중, 자신의 이전 형제 노드를 반환 한다. (텍스트 노드 포함)

2) Node.prototype.nextSibling
해당 노드의 형제 노드 중, 자신의 다음 형제 노드를 반환 한다. (텍스트 노드 포함)

3) Element.prototype.previousElementSibling
해당 노드의 형제 노드 중, 자신의 이전 형제 노드를 반환 한다. (반드시 요소 노드)

4) Element.prototype.nextElementSibling
해당 노드의 형제 노드 중, 자신의 다음 형제 노드를 반환 한다. (반드시 요소 노드)


노드 조작

노드 조작 메소드는 setter 프로퍼티가 포함된다.

1) Node.prototype.nodeValue
해당 노드 객체의 값을 반환한다. 해당 노드의 텍스트를 변경하고 싶을 경우 반드시 해당 노드의 텍스트 노드를 찾아 nodeValue 사용해야한다. (텍스트 노드가 아닐 경우 null을 반환한다.)

2) Node.prototype.textContent
해당 노드의 콘텐츠 영역 사이(시작 태그와 종료 태그의 사이)의 모든 텍스트들을 반환한다. 만약 해당 노드가 자식 태그를 가지고 있었다면, 해당 태그들의 자식 요소들의 텍스트 또한 반환된다. 이때, HTML 마크업은 무시된다.


DOM 구조 조작

DOM을 조작하여 새로운 노드가 DOM 트리 구조에 추가/삭제 될 경우 엔진은 렌더링을 위해 리플로우와 리페인트를 적용한다. DOM의 구조가 변경될 때마다 리플로우와 리페인트가 일어난다. (리플로우 : DOM구조에 새로운 노드가 추가/삭제 됨으로써 웹페이지의 구조가 변경되어 다시 도큐먼트의 레이아웃을 계산하는 과정 / 리페인트: DOM구조의 변화 혹은 CSS의 변화로 인해 페이지의 렌더링이 다시 요구되는 과정)

0) Element.prototype.innerHTML

해당 노드의 마크업을 취득하거나 변경한다. 해당 노드의 콘텐츠 영역에 존재하는 모든 HTML 마크업을 문자열로 반환한다.
➥ 마크업을 스크립트를 통해 직접적으로 HTML 도큐먼트에 삽입하기 때문에 보안 공격에 취약할 수 있다.

1) Document.prototype.createElement

태그네임을 인수로 전달받아 해당 태그네임을 갖는 노드를 생성해 반환한다. 이렇게 생성된 새로운 노드는 따로 연결시켜주기 전까지 기존 DOM 트리구조에 반영되지 않는다.

2) Document.prototype.createTextNode

문자열을 인수로 전달받아 해당 문자열을 가진 텍스트 노드를 생성해 반환한다. 이 또한 기존 DOM 트리구조에 반영되지 않아 추가적인 연결 과정이 필요하다.

3) Node.prototype.appendChild

노드를 전달받아 해당 노드를 appendChild를 호출한 노드의 마지막 자식 노드로 추가한뒤 반환한다.

4) Element.prototype.append

전달된 문자열, 노드를 메소드를 호출한 노드의 마지막 자식 노드로 추가한다. 어떠한 값도 반환하지 않으며, 문자열, 복수의 인수를 추가할 수 있다는 점이 appendChild 메소드와의 차이점이다.

➥ appendChild / append 메소드는 해당 노드를 복사해 붙여넣는 것이 아니라, 이미 존재하는 노드의 위치를 이동시키는 것이다. (복사해 붙여 넣을 경우 의도하지 않은 문제점(복수의 id 발생 등)이 발생하기 때문에 복사 기능을 가지지 않는다.) 따라서, 이미 존재하는 노드는 삭제되고 지정한 위치에 현재 노드가 지정된다.

5) DocumentFragment

Document Fragment 노드는 복수의 노드를 DOM에 추가할 때 사용된다. Document Fragment를 새롭게 추가할 노드들의 컨테이너로 사용함으로써, 불필요한 요소가 DOM에 추가되는 것을 막고, 리렌더링(리플로우, 리페인트) 과정을 줄인다. Document Fragment는 DOM에 추가될 시, 자신은 DOM에 추가하지 않고 삭제하며 자신의 자식요소들을 DOM에 추가시킨다.

Document Fragment 또한 하나의 인터페이스로, 다양한 메소드 및 생성자 함수로 새로운 Document Fragment 노드를 생성할 수 있다. Document.createDocumentFragment 메소드를 통해 생성할 수도 있다.

6) Node.prototype.cloneNode([deep : true/false])

깊은 복사에 대한 불리언 값을 전달 인자로 받아 해당 메소드를 호출한 노드를 복사해 반환한다. 얕은 복사를 사용해 노드를 복사할 경우 해당 노드의 자식 노드들은 복사되지 않는다.

7) Node.prototype.replaceChild (newcChild, oldChild)
자신을 호출한 노드의 자식 노드 중 oldChild에 해당하는 노드를 newChild로 교체한다.

8) Node.prototype.removeChild
해당 자식 노드를 삭제한다. 인수로 전달된 노드가 메소드를 호출한 자식노드일 때만 삭제가 가능하다.


어트리뷰트 조작

노드들의 어트리뷰트는 NamedNodeMap 이라는 유사배열객체에 담겨 요소 노드의 attributes 프로퍼티에 할당된다. attributes 프로퍼티는 read-only 이다.

HTML 요소들의 어트리뷰트는 요소에 따라, 초기값을 그대로 사용할 수도 사용자에 의해 그 값이 변경될 수도 있다. 노드 내의 attribute 프로퍼티는 HTML 요소의 어트리뷰트 초기 값을 저장하고 있다. 사용자에 의해 값이 변경이 될 수 있는 어트리뷰트들은 DOM 내의 프로퍼티에 그 변경된 값들이 할당 되어 있으며 이 프로퍼티를 변경하는 것으로 그 값을 조작할 수 있다. 또한 HTML 요소들의 어트리뷰트는 모두 문자열 값을 가지나, DOM 프로퍼티의 값은 다양한 자료형을 가질 수 있다.

1) Element.prototype.get/setAttribute(attribute name)

해당 메소드를 통해 해당 노드의 어트리뷰트 값을 받아 읽을 수도, 변경할 수도 있다. (초기값 수정)

2) Element.prototype.removeAttribute

해당 메소드를 통해 해당 노드의 어트리뷰트 값을 삭제할 수 있다. (초기값 수정)

• 대표적인 DOM 내의 프로퍼티 값 (프로퍼티 <-> 어트리뷰트)
id <-> id
value(input 요소)<-> value
className, classList <-> class
htmlFor <-> for
...

3) data 어트리뷰트를 통해 사용자 임의의 어트리뷰트를 DOM 내에서 사용할 수 있다.

HTML 요소 내에서 'data-anyname' 형태를 가진 어트리뷰트를 사용해 값을 지정할 경우 DOM의 해당 노드에는 dataset 객체 안에 해당 어트리뷰트 값('data-'가 제거되고 카멜케이스로 변환시킨)이 저장된다. 따라서 임의의 어트리뷰트를 node.dataset.anyName 을 통해 접근해 사용할 수 있다. 역으로 HTML 요소에 사용자 임의의 어트리뷰트를 추가할 수도 있다.


클래스 어트리뷰트 조작

HTML 요소에 클래스 어트리뷰트를 지정해주었다면 DOM 내의 프로퍼티인 className 과 classList 를 통해 클래스 어트리뷰트의 값의 추가/삭제/변경이 가능하다. 또한 classList 는 클래스 값들을 담은 DOMTokenList 를 값으로 반환하는데, DOMTokenList는 클래스 조작에 유용한 메소드들을 제공한다.

1)Element.prototype.className (setter, getter)

해당 노드의 클래스 어트리뷰트의 값을 획득하거나 변경한다. 클래스 어트리뷰트에 할당되어 있는 모든 값을 문자열로 반환한다. (공백 포함)

2)Element.prototype.classList (setter, getter)

해당 노드의 클래스 어트리뷰트 값을 모두 객체 형식으로 담은 DOMTokenList 유사배열객체를 반환한다.

2-1) add(...className)
해당 클래스를 해당 노드의 클래스리스트에 프로퍼티로 추가한다.

2-2) remove(...className)
해당 클래스를 해당 노드의 클래스리스트에서 제거한다.

2-3) item(index)
해당 인덱스를 지닌 해당 노드의 클래스 프로퍼티를 반환한다.

2-4) replace(oldClassName, newClassName)
메소드를 호출한 해당 노드의 oldClassName 클래스를 newClassName으로 교환한다.

profile

0개의 댓글