본문 바로가기

프로그래밍/js

lessons 30. DOM

2023.03.05

자바스크립트 스터디 8회차

공부 사이트: https://poiemaweb.com/

30. DOM

브라우저의 렌더링 엔진은 웹 문서를 로드한 후, 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재한다. 이를 DOM이라 한다.

→ 모든 요소, 요소의 속성, 텍스트를 각각 객체로 만들고 트리구조로 구성한 것이 DOM이다

DOM은 자바스크립트를 통해 동적으로 변경할 수 있다. DOM에 접근하고 수정할 수 있는 프로퍼티/메소드를 갖는 자바스크립트 객체를 DOM API라 한다.

 

 

1) DOM tree

브라우저가 HTML 문서를 로드한 후 파싱하여 생성하는 모델을 의미한다. (객체 트리로 구조화)

DOM Tree

노드 설명
Document Node
(문서 노드)
트리의 최상위에 존재. Element, Attribute, Text Node에 접근하기 위해서는 문서 노드를 통해야 함.
DOM tree의 엔트리 포인트.
Element Node
(요소 노드)
HTML 요소를 표현. Attribute, Text Node에 접근하려면 Element Node를 찾아 접근해야 한다.
모든 Element Node는 HTMLElement 객체를 상속한 객체로 구성된다.
Attribute Node
(속성 노드)
HTML Element의 속성을 표현. Element의 일부로 표현되는 것이지 자식은 아님.
Element Node를 찾아 접근하면 속성을 참조/수정할 수 있다.
Text Node
(텍스트 노드)
HTML Element의 Text를 표현. Element Node의 자식이며, DOM tree의 최종단이다.

 

 

2) DOM Query / Traversing

 

// TEST Page

<!DOCTYPE html>
<html>
  <head>
    <style>
      .red  { color: #ff0000; }
      .blue { color: #0000ff; }
    </style>
  </head>
  <body>
    <div>
      <h1>Cities</h1>
      <ul>
        <li id="one" class="red">Seoul</li>
        <li id="two" class="red">London</li>
        <li id="three" class="red">Newyork</li>
        <li id="four">Tokyo</li>
      </ul>
    </div>
  </body>
</html>

 

●  하나의 요소 노드 선택

① document.getElementById(id)

: id 속성 값으로 요소 노드를 하나 선택. 복수개가 선택된 경우, 첫 번째 요소만 반환한다.

② document.querySelector(cssSelector)

: CSS Selector를 통해 요소 노드를 하나 선택. 복수개가 선택된 경우, 첫 번째 요소만 반환한다.

 

 

 

●  여러 개의 요소 노드 선택

① document.getElementsByClassName(class)

: class 속성 값으로 요소 노드를 모두 선택한다. 공백으로 구분하여 여러 class를 지정할 수 있다.

: 반환값은 HTMLCollection (live)

: live의 의미는 실시간으로 Node상태를 변경한다는 것.

 

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

for (let i = 0; i < elems.length; i++) {
  elems[i].className = 'blue';
}
// 코드 결과: 첫 번째 요소와 세 번째 요소만 blue로 변경된다.

실시간으로 Node 상태를 변경한다의 의미는...유사 배열 객체인 HTMLCollection의 요소들이 실시간으로 변경된다는 것이다. 반복문을 돌면서 더 이상 ClassName이 'red'가 아닌 요소들은 HTMLCollection에서 사라진다.

그래서 elems[i]에서 문제가 생긴다.

 

[ for문 루프 과정 ]

i = 0, 첫 번째 요소의 ClassName 'blue'로 변경 후 HTMLCollection에서 첫 번째 요소 제거

i = 1, elems[1]은 세 번째 요소를 의미하게 됨. ClassName 'blue'로 변경 후 HTMLCollection에서 세 번째 요소 제거

i = 2, elems.length 값은 1. 반복문은 종료된다. (또한 elems[2]도 존재하지 않음)

 

이런 경우 해결하기 위해 4가지 방법을 사용할 수 있다.

반복문을 역방향으로 사용

 while 반복문을 사용

 HTMLCollection을 배열로 변경  (권장)

 querySelectorAll 메소드를 사용하여 HTMLCollection(live)가 아닌 NodeList(non-live)를 반환하도록 함

반복문 역방향 사용
while 반복문 사용
HTMLCollection을 배열로 변경
querySelectorAll 메소드 사용

 

 

② document.getElementsByTagName(tagName)

: 태그명으로 요소 노드를 모두 선택

: 반환값은 HTMLCollection (live)

 

 

③ document.querySelectorAll(selector)

: 지정된 CSS Selector를 사용하여 요소 노드 모두 선택

: 반환값은 NodeList (non-live)

 

 

●  DOM Traversing (탐색)

① parentNode: 부모 노드를 탐색한다.

예제 실행 시 'Tokyo' 만 'blue'로 변경되는데..  이유는 다음과 같다.

elem.parentNode는 <ul></ul> 영역인데, 이 부분의 className을 'blue'로 변경하면 <ul class='blue'> 가 된다.

그럼 그 자식노드인 4개의 <li> 중 class가 없는 'Tokyo'만 색이 변경되는 것이다.

자식 노드의 클래스가 우선순위가 더 높다. 

 

 

② firstChild, lastChild: 자식 노드를 탐색한다.

이 프로퍼티들은 작동이 되지 않는데, 이유는 요소 사이의 공백/줄바꿈 문자 등을 텍스트노드로 취급하기 때문이라고 한다.

요소들을 다 이어주면 정상적으로 작동한다.

 

③ firstElementChild, lastElementChild

: 자식 노드를 탐색한다

: 요소 사이의 공백/줄바꿈 문자로 인한 문제를 해결한 프로퍼티이다. firstChild,  lastChild와 같은 기능을 한다.

 

④ hasChildNodes(): 자식노드가 있는지 확인하고 true/false 값을 반환한다.

 

⑤ childNodes

: 자식노드의 컬렉션을 반환한다. 텍스트 요소를 포함한 모든 자식요소를 반환.

: 반환값은 NodeList (non-live)

 

⑥ children

: 자식 노드의 컬렉션을 반환한다. 자식 요소 중에서 Element Type 요소만 반환.

: 반환값은 HTMLCollection(live)

 

⑦ previousSibling, nextSibling

: 형제 노드를 탐색한다. 텍스트 노드를 포함한 모든 형제 노드를 탐색.

 

⑧ previousElementSibling, nextElementSibling

: 형제 노드를 탐색한다. 형제 노드 중에서 Element Type 요소만을 탐색.

 

 

 

3) DOM Manipulation

● 텍스트 노드에 접근/수정

nodeValue 노드의 값은 반환하는 프로퍼티이다. 텍스트 노드일 경우 문자열을, 요소 노드일 경우 null을 반환한다.
nodeName 노드의 이름을 반환하는 프로퍼티이다.
nodeType
노드의 타입을 반환하는 프로퍼티이다.

 

[텍스트 노드 접근 과정]

① 해당 텍스트 노드의 부모 노드를 선택한다. (요소 노드)

② firstChild 프로퍼티를 사용하여 텍스트 노드를 탐색한다.

③ 텍스트 노드의 유일한 프로퍼티 nodeValue를 이용하여 텍스트를 얻는다.

④ nodeValue를 이용하여 텍스트를 수정한다.

 

const one = document.getElementById('one');
console.dir(one);

console.log(one.nodeName);
console.log(one.nodeType);

const textNode = one.firstChild;

console.log(textNode.nodeName);
console.log(textNode.nodeType);

console.log(textNode.nodeValue);

// nodeValue 프로퍼티 이용하여 텍스트 수정
textNode.nodeValue = 'Pusan';

 

 

● 속성 노드에 접근/수정

className class 속성 값을 취득/변경하고자 할 때 사용하는 프로퍼티이다.
classList add/remove/item/toggle/contains/replace 메소드를 제공한다. 
id id 속성 값을 취득/변경하고자 할 때 사용하는 프로퍼티이다.
hasAttribute(arrtibute) 지정 속성을 가지고 있는지 검사한다. true/false 반환
getAttribute(attribute) 속성 값을 가져온다.
setAttribute(attribute, value) 속성 값을 설정한다.
removeAttribute(attribute) 속성을 제거한다.

 

● HTML 콘텐츠 조작

textContent 요소의 텍스트 내용을 취득/변경할 수 있는 프로퍼티이다. (마크업 무시)
innerText 요소의 텍스트 내용을 취득/변경할 수 있는 프로퍼티이다.
사용하지 않는 것을 권장한다. (CSS 순종적, 느림)
innerHTML 해당 요소의 모든 자식 요소를 포함하는 모든 콘텐츠를 하나의 문자열로 취득할 수 있다. (마크업 포함)
그러나 마크업이 포함된 콘텐츠를 추가하는 것은 XSS에 취약하다.

 

●  DOM 조작 방식

innerHTML을 사용하지 않고 새로운 콘텐츠를 추가하는 방법 → DOM 직접 조작

createElement(tagName) 태그 이름을 인자로 전달하여 요소를 생성한다.
createTextNode(text) 텍스트를 인자로 전달하여 텍스트 노드를 생성한다.
appendChild(Node) 인자를 전달한 노드를 마지막 자식 요소로 DOM 트리에 추가한다.
removeChild(Node) 인자로 전달한 노드를 DOM 트리에서 제거한다.

 

[과정]

① createElement()를 이용하여 새로운 요소 노드 생성.

② createTextNode()를 이용하여 새로운 텍스트 노드 생성.

③ appendChild()를 이용하여 생성된 노드를 DOM tree에 추가하거나 removeChild() 통해 DOM tree에서 노드 제거

 

 

 

● insertAdjacentHTML(position, string)

인자로 전달한 텍스트를 HTML로  파싱하고 , 그 결과로 생성된 노드를 DOM 트리의 지정 위치에 삽입한다.

- position: 삽입 위치 (beforebegin, afterbegin, beforeend, afterend)

- string: 삽입할 요소를 표현한 몬자열

position

#<em>: 강조된 텍스트 표현

 

 

● innerHTML &  DOM 조작방식 &  insertAdjacentHTML()

① innerHTML

장점 ㅇ DOM 조작 방식에 비해 빠르고 간편함.
ㅇ 간편하게 문자열로 정의한 여러 요소를 DOM에 추가할 수 있음.
ㅇ 콘텐츠 취득 가능
단점 ㅇ XSS에 취약
ㅇ HTML을 다시 파싱함. → 비효율적

 

② DOM 조작 방식

장점 ㅇ 특정 노드 한 개를 DOM에 추가할 때 적합.
단점 ㅇ innerHTML보다 느리고 더 많은 코드 필요.

 

③ insertAdjacentHTML()

장점 ㅇ 간편하게 문자열로 정의된 여러 요소를 DOM에 추가 가능
ㅇ 삽입되는 위치 설정 가능
단점 ㅇ XSS에 취약 

 

 

4) style

- style 프로퍼티를 사용하면 inline 스타일 선언을 생성할 수 있다.

- 특정 요소에 inline 스타일을 지정하는 경우에 사용한다.

- style 프로퍼티의 값을 얻으려면 window.getComputedStyle()을 사용한다.

'프로그래밍 > js' 카테고리의 다른 글

lessons 32. 이벤트  (0) 2023.03.21
lessons 31. 동기식/비동기식 처리 모델  (0) 2023.03.03
lessons 29. 배열 고차 함수  (0) 2023.02.28
lessons 27~28. 배열  (0) 2023.02.28
lessons 25~26. 정규표현식, String 객체  (0) 2023.02.21