DOM (document of model)
문서 객체 모델.. 노드 객체들로 구성된 트리 자료구조를 말한다. DOM 트리 라고도 한다.
노드객체는 종류가있고, 상속 구조를 갖는다. 총 12종류의 노드타입이 있는데, 중요한 노드는 아래와 같다.
문서 노드 : 최상위 루트노드 document 객체. Document, HTMLDocument 인터페이스를 상속받는다.
요소 노드 : html 요소. Element 인터페이스를 상속받는다.
어트리뷰트 노드 : 요소의 어트리뷰트를 가리키는 객체. Attr을 상속받는다.
텍스트 노드 : html 요소의 텍스트를 가리키는 객체. 자식노드를 가질수없는 리프노드이다. CharacterData 인터페이스를 상속받는다.
모든 노드객체는 Object, EventTarget, Node 인터페이스를 상속받는다.
요소 취득 방법
document.getElementsByTagName('li')
document.getElementById('idName')
document.getElementByClassName('test')
//요소가 존재하지 않을때는 빈 HTMLCollection 객체를 반환.
document.querySelector('.test')
//요소가 존재하지 않을때는 null을 반환
document.querySelectorAll('.test')
//요소가 존재하지 않을때는 빈 NodeList 객체를 반환
CSS문법을 사용하는 querySelector, querySelectorAll은 getElementBy*** 보다 느리다.
하지만 더 구체적인 조건으로 요소 노드를 얻을 수 있고, 일관된 방식이다.
HTMLCollection과 NodeList
DOM 컬렉션 객체이며, 유사 배열 객체이면서 이터러블이다. for...of 문으로 순회 할수있고 스프레드 사용으로 배열로 변환할 수 있다.
HTMLCollection은 노드객체의 상태 변화를 실시간으로 반영한다(live 객체)
따라서 for문을 순회할 때, 상태변경을 반영하여 요소를 제거하거나 변경될 수 있기 때문에 주의해야한다.
- 역방향으로 순회하는방법으로 회피할수있다.
- while문을 사용하여 노드 객체가 남지않을때까지 순회하는것으로 회피할수있다. 그러나..
- 부작용을 발생시키는 원인인 HTMLCollection 객체를 배열로 변환하여 배열의 고차함수를 쓰는것이 낫다.
NodeList는 non-live 객체다. (실시간으로 노드객체의 상태변경을 반영하지않음)
단, childNodes 프로퍼티가 반환하는 NodeList 객체는 live 객체이므로 주의가 필요하다.
따라서 배열로 변환하여 사용하는것이 좋다.
Array.from이나 spread문법으로 간단하게 변환할 수 있다.
노드 탐색
노드탐색 프로퍼티는 getter만 존재하는 읽기 전용 접근자 프로퍼티다. 값 할당은 무시된다.
노드 탐색을 할때에는 공백 텍스트 노드에 주의해야한다. (공백 택스트 노드는 스페이스, 탭, 개행을 포함한다.)
자식노드 탐색 프로퍼티
Node.prototype.childNodes : 자식노드 모두탐색
Element.prototype.children : 자식노드중에서 요소노드만 찾아 HTMLCollection 반환
Node.prototype.firstChild : 첫번째 자식노드 반환
Node.prototype.lastChild : 마지막 자식노드 반환
Element.prototype.firstElementChild : 첫번째 자식 요소 노드반환
Element.prototype.lastElementChild : 마지막 자식 요소노드 반환
부모노드 탐색 프로퍼티
Node.prototype.parentNode
형제 노드 탐색 프로퍼티
Node.prototype.previousSibling : 부모가 같은 형제 노드 중에서, 자신 이전노드 반환
Node.prototype.nextSibling : 부모가 같은 형제 노드 중에서, 자신 다음노드 반환
Element.prototype.previousElementSibling : 부모가 같은 형제 노드 중에서, 자신 이전 요소노드 반환
Element.prototype.nextElementSibling : 부모가 같은 형제 노드 중에서, 자신 다음 요소노드 반환
노드 정보 취득 프로퍼티
Node.prototype.nodeType
Node.prototype.nodeName
요소 노드의 텍스트 조작
Node.prototype.nodeValue : setter getter 모두 존재하는 접근자 프로퍼티. 텍스트노드만 참조가능.
Node.prototype.textContent : setter getter 모두 존재하는 접근자 프로퍼티. 요소노드의 텍스트를 모두 반환
(사이에 있는 HTML마크업은 파싱되지않음)
DOM 조작
새로운 노드를 생성, 수정, 삭제하는 것. 리플로우와 리페인트가 발생한다.
Element.prototype.innerHTML : 컨텐츠영역 내에 포함된 HTML 마크업을 문자열로 반환한다.
document.getElementById('header').innerHTML = "HI <span>rumi!</span>"
사용자 입력을 받아 그대로 innerHTML프로퍼티에 할당하는것은 XSS(Cross-site Scripting attacks)에 취약하므로 위험하다.
HTML 새니티제이션 (HTML sanitization)은 사용자에게 입력받은 데이터로 인해 XSS를 예방하기 위해 잠재위험을 제거하는 기능을 말하는데, DOMPurify 라이브러리가 좋다.
Element.prototype.insertAdjacentHTML(position,DOMString) : 위치를 지정해 새로운 요소를 삽입한다.
document.getElementById('test').insertAdjacentHTML('beforebegin', '<p>test</p>');
// position에는 beforebegan, afterbegin, beforeend, afterend만 넘길 수 있다.
Node.prototype.appendChild : 요소노드를 마지막 자식 요소로 추가.
Document.prototype.createDocumentFragment 메서드는 비어있는 DocumentFragment 노드를 생성하여 반환한다.
Fragment에 요소 노드들을 자식으로 추가한다음, 마지막에 DOM에 추가하면 1번의 리플로우 리페인팅만 발생한다.
Node.prototype.insertBefore(newNode, childNode) : newNode를 childNode 앞에 삽입한다.
Node.prototype.cloneNode(true) : 노드를 복사하여 반환한다. 인자로는 깊은복사를 할것인지에 대한 boolean값을 받는다.
Node.prototype.replaceChild(newChild, oldChild) : 자신을 호출한 노드의 자식노드를 다른 노드로 교체한다.
Node.prototype.removeChild(child) : 인수로 전달한 노드를 삭제한다. 전달한 노드는 메서드를 호출한 노드의 자식이여야한다.
어트리뷰트 취득
요소노드의 모든 어트리뷰트 노드는, Element.prototype.attributes 프로퍼티로 취득할수있다.
getter만 존재하는 읽기전용 접근자 프로퍼티이다.
attributes프로퍼티를 거치지 않고 변경하거나 참조하려면 Element.prototype.getAttribute/setAttribute 메서드를 사용한다.
document.getElementById('test').attributes.id.value;
document.getElementById('test').attributes.type.value;
document.getElementById('test').getAttribute('value')
document.getElementById('test').setAttribute('value', 'test')
Element.prototype.removeAttribute(attributeName) : 어트리뷰트를 삭제한다.
1. 요소 노드의 attribute
2. DOM 프로퍼티. ( DOM 프로퍼티들은 HTML 어트리뷰트값을 초기값으로 가지고 있다 )
HTML 어트리뷰트의 역할은 HTML요소의 초기상태를 지정하는것이고, 이는 변하지 않는다.
요소 노드는 2개의 상태, 초기 상태와 최신 상태를 관리해야하는데, 초기상태는 어트리뷰트 노드가 관리하고
최신 상태는 DOM 프로퍼티가 관리한다.
document.querySelector('.gLFyf').getAttribute('value')
// 구글 메인화면 input value 어트리뷰트값이다. 초기값이므로 항상 빈값이다.
document.querySelector('.gLFyf').value
// 내가 입력한 값이 나타난다.
<input type="checkbox" id="check1" checked/>
// 초기값은 true, 사용자가 클릭시 checked 프로퍼티의 상태는 false가 되지만, 어트리뷰트는 반영되지않는다!!!
const checkbox = document.getElementById('check1');
console.log(checkbox.getAttribute(checked)) // attribute value가 없으므로 빈값
console.log(checkbox.chekced) // 프로퍼티 최신 상태
<input type="checkbox" id="check1" checked="false"/>
<input type="checkbox" id="check1" checked="mol?ru"/>
// checked 어트리뷰트가 있는거라 true임...!!
와이건 이제야 알았네; 어트리뷰트와 프로퍼티를 혼동하지말자.
data 어트리뷰트와 dataset 프로퍼티
사용자 정의 어트리뷰트와 JS간에 데이터를 교환할 수 있다.
<ul class="user">
<li id="1" data-user-name="rumi" data-user-number="100">rumi</li>
<li id="2" data-user-name="ray" data-user-number="99">ray</li>
</ul>
const user = [...document.querySelector('.user').children];
console.log(user[0].dataset.userNumber) // 100
스타일
HTMLElement.prototype.style 는 getter, setter 모두 존재하며 요소노드의 인라인 스타일을 취득하거나 추가 또는 변경하는 프로퍼티다. 카멜케이스를 쓰고, 케밥케이스로 쓰려면 대괄호 표기법을 따른다.
const ul = document.querySelector('ul');
ul.style.backgroundColor= 'blue';
ul.style['background-color']= 'red';
클래스 조작 하려면 아래의 프로퍼티를 사용한다.
Element.prototype.className : class 어트리뷰트값을 취득하거나 변경
Element.prototype.classList : class어트리뷰트의 정보를담은 DOMTokenList 객체를 반환
replace, remove, add, item, contains 등의 메서드를 가진다.
요소에 적용되어있는 CSS스타일을 참조하려면, (인라인이든 클래스든 최종적으로 적용된 스타일)
window.getComputedStyle(el) 을 사용한다.
<div style="color:red">
<p>test</p>
</div>
...
const div = document.querySelector('div');
const computedStyle = window.getComputedStyle(div);
console.log(computedStyle.width); // 539px
console.log(computedStyle.color); // rgb(255,0,0);
'[STUDY] 스터디 > Deep Dive JS' 카테고리의 다른 글
js 타이머 (0) | 2023.01.28 |
---|---|
js 이벤트 (1) | 2023.01.28 |
js 브라우저 렌더링과정 (0) | 2023.01.22 |
js Set과 Map (0) | 2023.01.14 |
js 이터러블과 스프레드(...)문법 그리고 디스트럭처링 할당 (0) | 2023.01.14 |