[JavaScript] DOM

박우현·2020년 12월 26일
0
post-thumbnail

👌 DOM (Document Object Model)이란?

문서 객체 모델 (DOM, Document Object Model)은 XML이나 HTML 문서에 접근하기 위한 일종의 인터페이스. 이 객체 모델은 문서 내의 모든 요소를 정의하고, 각각의 요소에 접근하는 방법을 제공. 모든 문서의 요소를 각각의 객체로 만들고 이들 객체를 트리구조로 구성한 것. 정적인 웹페이지에 접근하여 동적으로 웹페이지를 변경하기 위하여 메모리 상에 존재하는 DOM을 변경하는 것이 JavaScript의 역할

✔ DOM의 기능

JavaScript는 DOM을 이용하여 다음과 같은 작업을 수행가능

  • 새로운 HTML 요소나 속성 추가
  • 존재하는 HTML 요소나 속성 제거
  • HTML 요소를 변경
  • HTML 속성을 변경
  • HTML CSS 스타일을 변경
  • HTML 이벤트를 추가
  • HTML 이벤트에 반응

✔ DOM Tree

DOM에서 모든 요소, 어트리뷰트, 텍스트는 하나의 객체이며 Document 객체의 자식

DOM Tree는 4종류의 노드로 구성

  • 문서 노드(Document Node): 트리의 최상위에 위치하며 각각 요소, 어트리뷰트, 텍스트 노드에 접근하기 위한 시작점
  • 요소 노드(Element Node): 요소 노드는 HTML 요소를 표현. HTML 요소는 중첩에 의해 부자 관계를 가지며, 이 부자 관계를 통해 정보를 구조화.
  • 어트리뷰트 노드(Atrribute Node): HTML 요소의 어트리뷰트를 표현. 어트리뷰트 노드는 해당 요소의 자식이 아니라 일부로 표현되므로 해당 요소를 찾아 접근하면 어트리뷰트를 참조, 수정 가능
  • 텍스트 노드(Text Node): 텍스트 노드는 HTML 요소의 텍스트를 표현. 텍스트 노드는 요소 노드의 자식이며 자신의 자식 노드를 가질 수 없다. 텍스트 노드는 DOM tree의 최종단

✔ DOM 접근

document.getElementById(id): id 값으로 요소 노드 한개 선택, 복수개가 존재할 경우 첫번째만 반환, HTMLElement return
document.querySelector(cssSelector): CSS 셀렉터를 사용하여 요소 노드 한개 선택, 복수개가 존재할 경우 첫번째만 반환, HTMLElement return
document.getElementsByClassName(class): class 값으로 요소 노드를 모두 선택, 공백으로 구분하여 여러 개의 class를 지정 가능, HTMLCollection(live) return

*여러 요소의 상태 변경시 주의할 점

const elems = document.getElementsByClassName('blue');

for (let i = 0; i < elems.length; i++){
	elems[i].className = 'blue';
}

위 예제는 제대로 동작하지 않음. 이유는?

getElementsByClassName의 반환값은 HTMLCollection이고, 이것은 배열과 비슷한 사용법을 가지고 있지만 실시간으로 Node의 상태 변경을 반영한다. E.g. 첫번째 loop을 돌리면 loop이 완료된 요소는 곧바로 삭제된다. 따라서 HTMLCollection에는 2개의 요소만 남게 되고, 다음 loop에 들어갔을 때 elems[1], 즉 원래대로라면 2번째 요소가 선택되었어야 할 때, 3번째 요소가 선택되어 1,3번째 요소만 상태가 변경되게 된다.

여러가지 해결방안이 있지만 그중에서도

  • HTMLCollection을 배열로 변경
const elems = document.getElementsByClassName('blue');
[... elems].forEach(elem => elem.className = 'blue');
  • querySelectorAll 메소드를 사용하여 HTMLCollection(live)가 아닌 NodeList(non-live)를 반환
const elems = document.querySelectorAll('.blue');
[...elems].forEach(elem => elem.className = 'blue');

document.getElementsByTagName(tagName): 태그명으로 요소 노드를 모두 선택, HTMLCollection(live) return
document.querySelectorAll(selector): 지정된 CSS 선택자를 사용해 요소 노드를 모두 선택, NodeList(non-live) return
parentNode: 부모노드 탐색, HTMLElement return
firstElementChild, lastElementChild: 자식노드 탐색, HTMLElement return
hasChildNodes(): 자식노드 유무를 확인, boolean return
childNodes: 자식노드의 컬렉션을 반환, 텍스트 요소를 포함, NodeList(non-live) return
children: 자식노드의 컬렉션을 반환, 텍스트 요소 미포함, HTMLCollection(live)
previousSibling, nextSibling: 형제노드 탐색 및 반환, 텍스트 요소 포함, HTMLElement return
previousElementSibling, nextElementSibling: 형제노드 탐색 및 반환, 텍스트 요소 미포함, HTMLElement return

✔ DOM 조작

  1. 텍스트 노드 조작
//텍스트 노드의 부모 노드 선택
cosnt one = document.getElementByID('one');
//firstChild를 이용해 텍스트 노드 선택
const textNode = one.firstChild;
//텍스트 노드의 유일한 프로퍼티인 nodeValue를 이용해 텍스트 수정
textNode.nodeValue = 'Seoul';
  1. 어트리뷰트 노드 조작
    className: class 값을 취득 또는 변경, 값을 할당하는 경우 class 값이 존재하지 않으면 생성하고 지정된 값을 설정, class 값이 여러개일 경우, 공백으로 구분된 문자열이 반환되므로 String 메소드 split(' ')을 사용하여 배열로 변경
    classList: add, remove, item, toggle, contains, replace 메소드 제공
    id: id 어트리뷰트의 값을 취득 또는 변경, 값을 할당하는 경우 id 값이 존재하지 않으면 생성하고 지정된 값을 설정
    hastAtrribute(attribute): 지정한 어트리뷰트를 가지고 있는지 검사, boolean return
    getAttribute(attribute): 어트리뷰트의 값을 취득, 문자열 return
    setAtrribute(attribute, value): 어트리뷰트와 값을 설정, undefined return
    removeAttribute(attribute): 지정한 어트리뷰트 제거, undefined return

👍 참고 사이트

0개의 댓글