DOM은 HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API, 즉 프로퍼티와 메서드를 제공하는 트리 자료구조다.
노드들의 계층구조로 이뤄진다. 부모노드와 자식노드로 구성되어 노드 간 계층적 구조를 표현하는 비선형 자료구조이다.
노드 객체들로 구성된 트리 자료구조를 DOM이라 한다.
DOM 트리의 최상위에 존재하는 루트노드로써 document 객체를 가리킨다. 진입점 역할을 하며 다른 노드에 접근하려면 문서 노드를 통해야한다.
HTML 요소를 가리키는 객체이다. 문서의 구조를 표현한다.
HTML 요소의 어트리뷰트를 가리키는 객체이다.
문서의 정보를 표현한다.
DOM은 HTML 문서의 계층적 구조와 정보를 표현하는 것은 물론 노드 객체의 종류, 즉 노드 타입에 따라 필요한 기능을 프로퍼티와 메서드의 집합인 DOM API로 제공한다. 이 DOM API를 통해 HTML의 구조나 내용 또는 스타일 등을 동적으로 조작할 수 있다.
<!DOCTYPE html>
<html>
<body>
<ul>
<li id="apple">Apple</li>
<li id="banana">Banana</li>
<li id="orange">Orange</li>
</ul>
<script>
const $elem = document.getElementById('banana');
$elem.style.color = 'red';
</script>
</body>
</html>
getElementById 메서든느 id어트리뷰트 값을 갖는 요소 노드를 탐색해서 반환한다.
중복된 id 값이 여러개라도 에러가 발생하지 않고 첫 번째 요소를 반환한다.
id가 존재하지 않을 경우 null을 반환한다.
<!DOCTYPE html>
<html>
<body>
<ul>
<li id="apple">Apple</li>
<li id="banana">Banana</li>
<li id="orange">Orange</li>
</ul>
<script>
const $elems = document.getElementsByTagName('li');
.
[...$elems].forEach(elem => { elem.style.color = 'red'; });
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<ul>
<li class="fruit apple">Apple</li>
<li class="fruit banana">Banana</li>
<li class="fruit orange">Orange</li>
</ul>
<script>
// class 값이 'fruit'인 요소 노드를 모두 탐색하여 HTMLCollection 객체에 담아 반환한다.
const $elems = document.getElementsByClassName('fruit');
// 취득한 모든 요소의 CSS color 프로퍼티 값을 변경한다.
[...$elems].forEach(elem => { elem.style.color = 'red'; });
// class 값이 'fruit apple'인 요소 노드를 모두 탐색하여 HTMLCollection 객체에 담아 반환한다.
const $apples = document.getElementsByClassName('fruit apple');
// 취득한 모든 요소 노드의 style.color 프로퍼티 값을 변경한다.
[...$apples].forEach(elem => { elem.style.color = 'blue'; });
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<ul>
<li class="apple">Apple</li>
<li class="banana">Banana</li>
<li class="orange">Orange</li>
</ul>
<script>
// ul 요소의 자식 요소인 li 요소를 모두 탐색하여 반환한다.
const $elems = document.querySelectorAll('ul > li');
// 취득한 요소 노드들은 NodeList 객체에 담겨 반환된다.
console.log($elems); // NodeList(3) [li.apple, li.banana, li.orange]
$elems.forEach(elem => { elem.style.color = 'red'; });
</script>
</body>
</html>
모두 유사 배열 객체이면서 이터러블이다. for...of를 사용할 수 있고 스프레드 문법 사용가능하다.
중요한 특징은 노드 객체의 상태변화를 실시간으로 반영하는 살아있는 객체이다.
HTMLCollection은 언제나 live 객체로 동작한다.
그러나 NodeList의 경우 실시간으로 반영하지 않고 과거의 정적 상태를 유지하는 non-live로 동작하지만 경우에 따라서 live 객체로 동작한다.
[...$elems].forEach(elem => elem.className = 'blue');
const $elems = document.querySelectorAll('.red');
$elems.forEach(elem => elem.className = 'blue');
노드 객체의 상태 변경과 상관없이 안전하게 DOM을 사용하려면 HTMLCollection이나 NodeList 객체를 배열로 변환하여 사용하는 것을 권장한다.
<!DOCTYPE html>
<html>
<body>
<div id="foo">Hello</div>
</body>
<script>
// 1. #foo 요소 노드의 자식 노드인 텍스트 노드를 취득한다.
const $textNode = document.getElementById('foo').firstChild;
// 2. nodeValue 프로퍼티를 사용하여 텍스트 노드의 값을 변경한다.
$textNode.nodeValue = 'World';
console.log($textNode.nodeValue); // World
</script>
</html>
<!DOCTYPE html>
<html>
<body>
<div id="foo">Hello <span>world!</span></div>
</body>
<script>
// #foo 요소 노드의 텍스트를 모두 취득한다. 이때 HTML 마크업은 무시된다.
console.log(document.getElementById('foo').textContent); // Hello world!
</script>
</html>
<!DOCTYPE html>
<html>
<body>
<div id="foo">Hello <span>world!</span></div>
</body>
<script>
// #foo 요소의 콘텐츠 영역 내의 HTML 마크업을 문자열로 취득한다.
console.log(document.getElementById('foo').innerHTML);
// "Hello <span>world!</span>"
</script>
</html>
<!DOCTYPE html>
<html>
<body>
<!-- beforebegin -->
<div id="foo">
<!-- afterbegin -->
text
<!-- beforeend -->
</div>
<!-- afterend -->
</body>
<script>
const $foo = document.getElementById('foo');
$foo.insertAdjacentHTML('beforebegin', '<p>beforebegin</p>');
$foo.insertAdjacentHTML('afterbegin', '<p>afterbegin</p>');
$foo.insertAdjacentHTML('beforeend', '<p>beforeend</p>');
$foo.insertAdjacentHTML('afterend', '<p>afterend</p>');
</script>
</html>
const $li = document.createElement('li');
const textNode = document.createTextNode('Banana');
$li.appendChild(textNode);
<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li>Apple</li>
<li>Banana</li>
</ul>
</body>
<script>
// 요소 노드 생성
const $li = document.createElement('li');
// 텍스트 노드를 $li 요소 노드의 마지막 자식 노드로 추가
$li.appendChild(document.createTextNode('Orange'));
// $li 요소 노드를 #fruits 요소 노드의 마지막 자식 노드로 추가
document.getElementById('fruits').appendChild($li);
</script>
</html>
<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li>Apple</li>
<li>Banana</li>
<li>Orange</li>
</ul>
</body>
<script>
const $fruits = document.getElementById('fruits');
// 이미 존재하는 요소 노드를 취득
const [$apple, $banana, ] = $fruits.children;
// 이미 존재하는 $apple 요소 노드를 #fruits 요소 노드의 마지막 노드로 이동
$fruits.appendChild($apple); // Banana - Orange - Apple
// 이미 존재하는 $banana 요소 노드를 #fruits 요소의 마지막 자식 노드 앞으로 이동
$fruits.insertBefore($banana, $fruits.lastElementChild);
// Orange - Banana - Apple
</script>
</html>
<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li>Apple</li>
</ul>
</body>
<script>
const $fruits = document.getElementById('fruits');
const $apple = $fruits.firstElementChild;
// $apple 요소를 얕은 복사하여 사본을 생성. 텍스트 노드가 없는 사본이 생성된다.
const $shallowClone = $apple.cloneNode();
// 사본 요소 노드에 텍스트 추가
$shallowClone.textContent = 'Banana';
// 사본 요소 노드를 #fruits 요소 노드의 마지막 노드로 추가
$fruits.appendChild($shallowClone);
// #fruits 요소를 깊은 복사하여 모든 자손 노드가 포함된 사본을 생성
const $deepClone = $fruits.cloneNode(true);
// 사본 요소 노드를 #fruits 요소 노드의 마지막 노드로 추가
$fruits.appendChild($deepClone);
</script>
</html>
<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li>Apple</li>
</ul>
</body>
<script>
const $fruits = document.getElementById('fruits');
// 기존 노드와 교체할 요소 노드를 생성
const $newChild = document.createElement('li');
$newChild.textContent = 'Banana';
// #fruits 요소 노드의 첫 번째 자식 요소 노드를 $newChild 요소 노드로 교체
$fruits.replaceChild($newChild, $fruits.firstElementChild);
</script>
</html>
<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li>Apple</li>
<li>Banana</li>
</ul>
</body>
<script>
const $fruits = document.getElementById('fruits');
// #fruits 요소 노드의 마지막 요소를 DOM에서 삭제
$fruits.removeChild($fruits.lastElementChild);
</script>
</html>
<input id="user" type="text" value="ungmo2">
HTML 문서의 구성 요소인 HTML 요소는 여러 개의 어트리뷰트(속성)을 가질 수 있다. HTML 요소의 동작을
제어하기 위한 추가적인 정보를 제공하는 HTML 어트리뷰트는 HTML 요소의 시작 태그에 어트리뷰트 이름 = 어티르뷰트 값 형식으로 정의한다.
<!DOCTYPE html>
<html>
<body>
<input id="user" type="text" value="ungmo2">
<script>
const $input = document.getElementById('user');
// value 어트리뷰트 값을 취득
const inputValue = $input.getAttribute('value');
console.log(inputValue); // ungmo2
// value 어트리뷰트 값을 변경
$input.setAttribute('value', 'foo');
console.log($input.getAttribute('value')); // foo
</script>
</body>
</html>