2023.03.05
자바스크립트 스터디 8회차
공부 사이트: https://poiemaweb.com/
30. DOM
브라우저의 렌더링 엔진은 웹 문서를 로드한 후, 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재한다. 이를 DOM이라 한다.
→ 모든 요소, 요소의 속성, 텍스트를 각각 객체로 만들고 트리구조로 구성한 것이 DOM이다
DOM은 자바스크립트를 통해 동적으로 변경할 수 있다. DOM에 접근하고 수정할 수 있는 프로퍼티/메소드를 갖는 자바스크립트 객체를 DOM API라 한다.
1) DOM tree
브라우저가 HTML 문서를 로드한 후 파싱하여 생성하는 모델을 의미한다. (객체 트리로 구조화)
노드 | 설명 |
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)를 반환하도록 함
② 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: 삽입할 요소를 표현한 몬자열
#<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 |