본문 바로가기
웹 프로그래밍 기초

DOM (1)

by oncerun 2022. 3. 12.
반응형

 

브라우저 렌더링 과정을 들어다 보면 HTML 텍스트 문서를 토큰으로 나누어 HTML 문서의 계층적 구조와 정보를 표현하고 이를 제어할 수 있는 DOM API를 제공하는 트리 자료구조를 DOM이라고 한다.

 

모델이라는 이름에 걸맞게 이는 객체가 아닌 HTML 각 요소를 모아 트리 자료구조 형태로 표현한 것을 DOM이라고 하는데 DOM의 내부를 조금만 들여다보자.

 

노드

 

HTML 요소는 HTML 문서를 구성하는 개별적인 요소를 의미한다. 

 

<div class="world">Hello</div>

이 div라는 HTML 요소는 시작 태그, 어트리뷰트의 값과 이름, 콘텐츠, 종료 태그로 이루어져 있다. 

 

이러한 요소가 렌더링 엔진에 의해 파싱 되어 DOM을 구성하는 하나의 요소 노드 객체로 변환된다. 이때 HTML 요소의 어트리뷰트는 어트리뷰트 노드로, HTML 요소의 텍스트 콘텐츠인 Hello는 텍스트 노드로 변환된다.

 

이 말은 HTML요소 노드 객체 내부에는 어트리뷰트를 표현하는 노드, 텍스트 콘텐츠를 나타내는 노드를 자식 노드로 가지고 있다는 이야기가 된다. 노드 객체는 종류가 존재하고 상속 수조를 갖는다. 노드 객체는 총 12개의 종류가 있다.  이 중에서 중요한 노드 타입은 4가지로 추릴 수 있다.

 

  • 문서 노드 (document node)
     문서 노드는 DOM 트리의 최상위에 존재하는 루트 노드로 document 객체를 가리킨다.  document 객체는 브라우저가 렌더링 한 HTML 문서 전체를 가리키는 객체로서 전역 객체 window의 document 프로퍼티에 바인딩되어 있다.

    브라우저 환경의 모든 자바스크립트 코드는 script 태그에 의해 분리되어 있어도 하나의 전역 객체 window를 공유한다. 따라서 모든 자바스크립트 코드는 전역 객체 window의 document프로퍼티에 바인딩되어 있는 하나의 document 객체를 바라본다. 

    루트 노드라는 것은 모든 탐색을 위한 시작점이라는 의미도 내포한다. 따라서 DOM 트리를 따라서 다른 노드에 접근하기 위해선 문서 노드를 통해야 한다.

  • 요소 노드 (element node)
    요소 노드는 HTML 요소를 가리키는 객체다. 요소 노드는 HTML 요소 간의 중첩에 의해 부자 관계를 가지며, 이 부자 관계를 통해 정보를 구조화한다. 따라서 요소 노드는 문서의 구조를 표현한다고 할 수 있다.

  • 어트리뷰트 노드 (attribute node)
    어트리뷰트 노드는 HTML 요소의 어트리뷰트를 가리키는 객체다. 어트리뷰트 노드는 어트리뷰트가 지정된 HTML 요소와 연결되어 있다. 
    요소 노드는 부모 노드와 연결관계를 갖지만 어트리뷰트 노드는 요소 노드에만 연결되어 있다. 그렇기에 이는 형제 노드라고 할 수 없다.  그리고 우리는 어트리뷰트 노드에 접근하여 참조하거나 변경하기 위해서는 우선 요소 노드에 접근해야 함을 알 수 있다.

  • 텍스트 노드 (text node)
    HTML 요소의 텍스트를 가리키는 객체이다. 텍스트 노드는 요소 노드의 자식 노드이며, 자식 노드를 가질 수 없는 리프 노드이다.  이는 텍스트 노드에 접근하기 위해선 부모 노드인 요소 노드에 접근해야 한다.

 

이외에도 Comment 노드, DocumentType 노드, DocumentFragment 노드 등 총 12개의 노드 타입이 존재한다.

 

 

 

DOM을 구성하는 노드 객체들은 ECMAScript 사양에 정의된 표준 빌트인 객체가 아닌 브라우저 환경에서 추가적으로 제공하는 호스트 객체이다. 하지만 노드 객체도 자바스크립트 객체이므로 프로토타입에 의한 상속 구조를 갖는다.

 

 

 

모든 노드 객체는 Object, EventTarget, Node 인터페이스를 상속받고 필요에 따라 추가적인 상속을 받게 된다. 

 

이러한 인터페이스들의 이름을 타입 스크립트의 타입에서 본 적이 있는 것 같다. 요소 노드를 가져온 적이 있는 데 이 가져온 노드를 무슨 타입으로 해야 할지 몰랐는데 vscode에서 추천하길 HTMLElement타입을 지정하라고 한 것 같다.

 

노드 객체에는 노드 타입에 상관없이 모든 노드 객체가 공통으로 갖는 기능도 있고 노드 타입에 따라 고유한 기능도 있다. 

 

예를 들어 모든 노드 객체 들어 공통적으로 이벤트를 발생시킬 수 있다.  이벤트에 관련된 기능은 EventTarget 인터페이스가 제공한다. 

또한 모든 노드 객체는 트리 자료구조의 노드로서 공통적으로 트리 탐색 기능이나 노드 정보 제공 기능이 필요하다. 이와 같은 노드 관련 기능은 Node 인터페이스가 제공한다.

 

HTML 요소 노드 객체는 HTML 요소가 갖는 공통적인 기능이 존재한다. HTML 요소가 갖는 공통적인 기능은 HTMLElement 인터페이스가 제공한다.

 

이처럼 DOM은 HTML 문서의 계층적 구조와 정보를 표현하는 것은 물론 노드 객체의 타입에 따라 필요한 기능을 프로퍼티와 메서드의 집합인 DOM API를 제공하고 이 DOM API를 통해 구조나 내용, 스타일 등을 동적으로 조정할 수 있다.

 

 

 

동적으로 내용, 구조, 스타일을 조정하기 위해서는 대개 요소 노드가 필요하다. 

그 이유는 요소 노드의 자식 노드로 텍스트 노드가 존재하고 요소 노드와 연결된 어트리뷰트 노드가 존재하기 때문이다.

 

요소 노드를 취득하는 방법은 매우 다양하게 존재한다. 

 

1. Document.prototype.getElementById 


 - 인수로 전달한 id 어트리뷰트 값을 갖는 하나의 요소 노드를 탐색 후 반환한다. document의 프로토타입 메서드이기 때문에 문서 노드인 document를 통해 호출해야 한다.

 

여기서 흥미로운 사실이 알았는데 HTML 요소에 id 어트리뷰트를 부여하면 id 값과 동일한 이름의 전역 변수가 암묵적으로 선언되고 해동 노드 객체가 할당되는 부수 효과가 있다는 것이다.

 

 

2. Document.protoype.getElementsByTagName

 

tag이름은 중복될 수 있다. 이는 인수로 전달된 태그 이름을 갖는 모든 요소 노도를 탐색하여 DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.

HTMLCollection  객체는 유사 배열 객체이면서 이 트러블이다.

 

만약 HTML 문서의 모든 요소 노드를 취득하려면 인수에 '*'를 전달한다.

 

getElementsByTagName 메서드는 Document의 프로토타입 메서드와 Element 프로토타입 메서드가 존재한다. 

 

Document 프로토타입 getElementsByTagName메서드는 DOM의 루트 노드인 document를 통해 호출하며 DOM 전체에서 요소 노드를 탐색하여 반환한다.

하지만 Element 프로토타입 getElementsByTagName메서드는 특정 요소 노드를 통해 호출하여 특정 요소 노드의 자손 노드 중에서 요소 노드를 탐색하여 반환한다.

 

이는 루트 노드에서부터 요소 노드를 찾는 것뿐만 아니라 모든 요소 노드에는 Element 인터페이스를 상속받고 있기 때문에 특정 요소 노드 기준 자손 노드를 태그 이름으로 한정되어 찾을 수 있다는 것이다.

 

3. Document.prototype / Element.prototype.getElementsByClassName

 

class 어트리뷰트 값을 갖는 모든 요소를 탐색하여 반환한다. 위와 동일하게 Document, Element 프로토타입 메서드에 정의되어있다.

 

 

 

4. CSS Selector

 

css selector는 스타일 적용하고자 하는 HTML 요소를 특정할 때 사용하는 문법이다. 

#은 id를 의미하고. 은 클래스를 *은 모든 요소 등등 css를 작성할 때 HTML 요소를 선택하는 방법이다.

  • 인수로 전달한 CSS 선택자를 만족시키는 요소 노드가 여러 개인 경우 첫 번째 요소 노드만 반환
  • 존재하지 않는 경우 null을 반환
  • CSS 선택자가 문법에 맞지 않는 경우 DOMException 에러가 발생

우리는 Document, Element 프로토타입 메서드인 querySelector, querySelectorAll을 통해 CSS selector를 사용할 수 있다.  이중 querySelectorAll은 만족시키는 여러 요소 노드 객체를 갖는 DOM 컬렉션 객체인 NodeList 객체를 반환한다. 

이 NodeList객체는 유사 배열 객체이면서 이터러블이다.

 

 

 

이렇게 요소 노드를 취득할 수 있는 방법은 다양하다. 하지만 특정 요소를 취득할 수 있는지 여부를 확인을 해야 한다.

이를 위해 Element.prototype.matches 메서드는 CSS 선택자를 통해 특정 요소를 취득할 수 있는지 확인한다.

 

 

 

 

반응형

'웹 프로그래밍 기초' 카테고리의 다른 글

[CSS] Cascade, specificity, inheritance  (1) 2023.04.10
DOM (2)  (0) 2022.03.12
브라우저의 렌더링 과정  (0) 2022.03.11
[css] z-index  (0) 2022.03.11
Canvas  (0) 2021.10.17

댓글