DOM

kailyn·2024년 10월 11일

Js

목록 보기
9/11
  • 브라우저는 HTML, CSS, 자바스크립트로 작성 된 텍스트 문서를 파싱하여 브라우저 렌더링한다.

    • 파싱(parsing) : 프로그래밍 언어의 문법에 맞게 작성 된 텍스트 문서를 읽어 들여 실행하기 위해 텍스트 문서의 문자열을 토큰으로 분해하고, 토큰에 문법적 의미와 구조를 반영하여 트리 구조의 자료 구조인 파스 트리(parse tree)를 생성하는 일련의 과정이다. 일반적으로 파싱 이후 파스 트리를 기반으로 중간 언어인 바이트 코드를 생성하고 실행한다.
    • 렌더링(rendering) : HTML, CSS, 자바스크립트로 작성 된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것이다.
  • DOM 구조

    • 브라우저 렌더링 엔진은 HTML 문서를 파싱하여 브라우저가 이해할 수 있는 자료 구조인 DOM을 생성한다.
    • HTML 문서를 파싱한 결과물로서 생성 된 DOM은 HTML 문서의 구조와 정보뿐만 아니라 HTML 요소와 스타일 등을 변경할 수 있는 프로그래밍 인터페이스로서 DOM API를 제공한다. 자바스크립트에서 DOM API를 사용하면 이미 생성 된 DOM을 동적으로 조작할 수 있다.
  • 노드

    • HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환된다. 이때 HTML 요소의 어트리뷰트는 어트리뷰트 노드로, HTML 요소의 텍스트 콘텐츠는 텍스트 노드로 변환 된다.
    • HTML 요소 간에는 중첩 관계에 의해 계층적인 부자 관계가 형성 된다.
      이러한 HTML 요소 간의 부자 관계를 반영하여 HTML 문서의 구성 요소인 HTML 요소를 객체화한 모든 노드 객체들을 트리 자료 구조로 구성한다.
      노드 객체들로 구성 된 트리 자료 구조를 DOM(Document Object Model)이라 한다. 이에 DOM 트리라는 명칭을 쓰기도 한다.

1. 요소 노드 가져오기

1-1. id로 요소 노드 가져오기

  • Document.prototype.getElementById 메서드는 인수로 전달한 id 어트리뷰트 값을 갖는 하나의 요소 노드를 탐색하여 반환한다.
  • 문서 내에 중복 된 id 값을 갖는 HTML 요소가 여러 개 존재하더라도 에러가 발생하지는 않지만 해당 id 값을 갖는 첫 번째 요소 노드만 반환한다.
  • id 값을 갖는 HTML 요소가 존재하지 않는 경우 null을 반환한다.

1-2. tag name으로 요소 노드 가져오기

  • Document.prototype/Element.prototype.getElementsByTagName 메서드는 인수로 전달한 태그 이름을 갖는 모든 요소 노드들을 탐색하여 반환한다.
  • 메서드 이름의 Elements가 복수형인 것에서 알 수 있듯 여러 개의 요소 노드 객체를 갖는 DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.
  • 해당 태그 이름을 갖는 요소가 존재하지 않을 경우 빈 HTMLCollection 객체 반환한다.

1-3. class로 요소 노드 가져오기

  • Document.prototype/Element.prototype.getElementsByClassName 메서드는 인수로 전달한 class 어트리뷰트 값을 갖는 모든 요소 노드들을 탐색하여 반환한다.
  • 인수로 전달할 class 값은 공백으로 구분하여 여러 개의 class를 지정할 수 있다.
  • 메서드 이름의 Elements가 복수형인 것에서 알 수 있듯 여러 개의 요소 노드 객체를 갖는 DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.
  • 해당 class를 갖는 요소가 존재하지 않을 경우 빈 HTMLCollection 객체 반환한다.

1-4. css 선택자를 활용한 요소 노드 가져오기

  • Document.prototype/Element.prototype.querySelector 메서드는 인수로 전달한 CSS 선택자를 만족시키는 하나의 요소 노드를 탐색하여 반환한다.
  • CSS 선택자를 만족시키는 요소 노드가 존재하지 않는 경우 null을 반환한다.

1-5. HTMLCollection과 NodeList

  • HTMLCollection과 NodeList는 DOM API가 여러 개의 결과 값을 반환하기 위한 DOM 컬렉션 객체이다.
  • HTMLCollection과 NodeList는 모두 유사 배열 객체면서 이터러블이다. 따라서 for...of 문으로 순회할 수 있으며 배열로 변환할 수 있다.
  • HTMLCollection
    • getElementsByTagName, getElementsByClassName 메서드가 반환하는 객체이다.
    • 노드 객체의 상태 변화를 실시간으로 반영하는 살아있는(live) DOM 컬렉션 객체이다.
    • HTMLCollection 객체는 실시간으로 노드 객체의 상태 변경을 반영하여 요소를 제거할 수 있기 때문에 for문으로 순회하면서 노드 객체의 상태를 변경하는 경우 주의해야 한다.
      • 반복문 역방향 순회 혹은 while문 사용 등을 통해 회피할 수 있다.
      • 하지만 HTMLCollection 객체를 사용하지 않고 배열로 변환하는 것이 권장 된다.
  • NodeList
    • querySelectorAll 메서드가 반환하는 객체이다.
    • 실시간으로 노드 객체의 상태를 변경하지 않기(non-live) 때문에 HTMLCollection의 부작용을 해결할 수 있다.
    • NodeList 객체는 NodeList.prototype.forEach 메서드를 상속 받아 사용할 수 있다.
    • NodeList.prototype은 forEach 외에도 item, entries, keys, values 메서드를 제공한다.
    • 대부분의 NodeList는 non-live 객체로 동작하지만 childNodes 프로퍼티가 반환하는 NodeList 객체는 HTMLCollection 객체와 같이 실시간으로 노드 객체의 상태 변경을 반영하는 live 객체로 동작하므로 주의가 필요하다.

2. 노드 순회

  • 요소를 취득한 다음, 취득한 요소를 기점으로 DOM 트리의 노드를 옮겨다니며 부모, 형제, 자식 노드 등을 탐색(traversinig)해야 할 때가 있다. DOM 트리 상의 노드를 탐색할 수 있도록 Node, Element 인터페이스는 트리 탐색 프로퍼티를 제공한다. 노드 탐색 프로퍼티는 모두 참조만 가능한 읽기 전용 접근자 프로퍼티이다. 읽기 전용 접근자 프로퍼티에 값을 할당하면 아무런 에러 없이 무시된다.
    • 공백 텍스트 노드
      • HTML 요소 사이의 스페이스, 탭, 줄바꿈(개행) 등의 공백 문자는 텍스트 노드를 생성한다.

2-1. 자식 노드

  • Element.prototype.firstElementChild : 첫 번째 자식 요소 노드 반환
  • Element.prototype.lastElementChild : 마지막 자식 요소 노드 반환

2-2. 부모 노드

  • 부모 노드를 탐색하려면 Node.prototype.parentNode 프로퍼티를 사용한다.
  • 텍스트 노드는 DOM 트리의 최종단 노드인 리프 노드(leaf node)이므로 부모가 텍스트 노드인 경우는 없다.

2-3. 형제 노드

  • Node.prototype.previousSibling : 형제 노드 중 자신의 이전 형제 노드(요소 노드, 텍스트 노드)를 탐색하여 반환
  • Node.prototype.nextSibling : 형제 노드 중 자신의 다음 형제 노드(요소 노드, 텍스트 노드)를 탐생하여 반환

3. DOM 수정

3-1. innerHTML

  • Element.prototype.innerHTML 프로퍼티는 setter와 getter 모두 존재하는 접근자 프로퍼티로 요소 노드의 HTML 마크업을 취득하거나 변경한다.
  • textContent 프로퍼티는 HTML 마크업을 무시하고 텍스트만 반환하지만 innerHTML 프로퍼티는 HTML 마크업이 포함 된 문자열을 그대로 반환한다.
  • innerHTML 프로퍼티를 사용한 DOM 조작은 구현이 간단하고 직관적이라는 장점이 있다.
  • 하지만 사용자로부터 입력받은 데이터를 그대로 innerHTML 프로퍼티에 할당하는 것은 XSS(Cross-Site Scripting Attacks)에 취약하므로 위험하다는 단점도 있다. HTML 마크업 내에 자바스크립트 악성 코드가 포함 되어 있다면 파싱 과정에서 그대로 실행 될 가능성이 있다.
  • innerHTML 프로퍼티에 HTML 마크업 문자열을 할당하는 경우 요소 노드의 모든 자식 노드를 제거하고 할당한 HTML 마크업 문자열을 파싱하여 DOM을 변경한다는 단점이 있다. 또한, 새로운 요소를 삽입할 때 삽입될 위치를 지정할 수 없다는 단점도 있다.

3-2. insertAdjacentHTML

  • Element.prototype.insertAdjacentHTML(position, DOMString) 메서드는 기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입한다.
  • 첫번째 인수로 전달할 수 있는 문자열은 'beforebegin', 'afterbegin', 'beforeend', 'afterend'의 4가지이다.
  • insertAdjacentHTML 메서드는 기존 요소에 영향을 주지 않고 새롭게 삽입될 요소만을 파싱하여 자식 요소로 추가하므로 기존의 자식 노드를 모드 제거하고 다시 처음부터 새롭게 자식 노드를 생성하여 자식 요소로
    추가하는 innerHTML 프로퍼티보다 효율적이고 빠르다. 단, HTML 마크업 문자열을 파싱하므로 크로스 사이트 스크립팅 공격에 취약하다는 점은 동일하다.

3-3. node-create-append

  • Document.prototype.createElement(tagName) : 인수로 전달받은 태그 이름에 해당하는 요소 노드를 생성하여 반환
  • Document.prototype.createTextNode(text) : 인수로 전달받은 텍스트 값으로 텍스트 노드를 생성하여 반환
  • Node.prototype.appendChild(childNode) : 인수로 전달받은 노드를 appendChild 메서드를 호출한 노드의 마지막 자식 노드로 추가

4. 어트리뷰트(attribute)

4-1. 어트리뷰트

  • Element.prototype.attributes 프로퍼티로 모든 어트리뷰트 노드를 취득할 수 있다.
  • attributes 프로퍼티는 getter만 존재하는 읽기 전용 접근자 프로퍼티로 NameNodeMap 객체를 반환한다.
  • Element.prototype.getAttribute/setAttribute 메서드를 사용하면 attributes 프로퍼티를 통하지 않고 요소 노드에서 메서드를 통해 직접 HTML 어트리뷰트 값을 취득하거나 변경할 수 있어 편리하다.
  • Element.prototype.hasAttribute(attributeName) 메서드를 사용하면 특정 HTML 어트리뷰트가 존재하는지 확인할 수 있다.
  • Element.prototype.removeAttribute(attributeName) 메서드를 사용하면 특정 HTML 어트리뷰트를 삭제할 수 있다.

4-2. 어트리뷰트와 프로퍼티

  • HTML 어트리뷰트 : HTML 요소의 초기 상태를 지정하며 변하지 않는다.
    • 어트리뷰트 노드에서 관리 되며 값을 얻거나 변경하려면 getAttribute/setAttribute 메서드를 사용한다.
  • DOM 프로퍼티 : 사용자가 입력한 최신 상태를 관리한다.
    • 사용자의 입력에 의한 상태 변화에 반응하여 언제나 최신 상태를 유지한다.
  • getAttribute 메서드로 취득한 어트리뷰트 값은 언제나 문자열이다.
  • 하지만 DOM 프로퍼티로 취득한 최신 상태 값은 문자열이 아닐 수 있다.
  • checkbox 요소의 checked 어트리뷰트 값은 문자열이지만 checked 프로퍼티 값은 불리언 타입이다.

5. Style

5-1. inline-style

  • HTMLElement.prototype.style 프로퍼티는 setter와 getter가 모두 존재하는 접근자 프로퍼티로 요소 노드의 인라인 스타일을 취득하거나 추가 또는 변경한다.
  • HTMLElement.prototype.style 프로퍼티는 CSSStyleDeclaration 타입의 객체 반환하는데 이 프로퍼티에 값을 할당하면 해당 CSS 프로퍼티가 인라인 스타일로 HTML 요소에 추가되거나 변경 된다.

5-2. className-classList

  • class 어트리뷰트에 대응하는 DOM 프로퍼티는 class가 아니라 className, classList이다.
  • Element.prototype.className 프로퍼티는 setter와 getter 모두 존재하는 접근자 프로퍼티로 요소 노드의 className 프로퍼티를 참조하면 class 어트리뷰트의 값을 문자열로 반환하고, 요소 노드의 className 프로퍼티에 문자열을 할당하면 class 어트리뷰트 값을 할당한 문자열로 변경한다.
  • Element.prototype.classList 프로퍼티는 class 어트리뷰트의 정보를 담은 DOMTokenList 객체를 반환한다.
profile
나는 할 수 있다...!

0개의 댓글