본문 바로가기
Front-End/JavaScript

39장 DOM (모던 자바스크립트 Deep Dive)

by kk님 2023. 5. 25.

 

모던 자바스크립트 Deep Dive 글 목록(스터디)
https://hello-kk.tistory.com/780


★DOM 조작에 의해 리플로우, 리페인트 발생 (성능 최적화 고려)★

innerHTML (setter/getter) (1) 모든 자식노드를 삭제한 후
(2) 새롭게 노드를 생성
하여
(3) 자식 요소로 추가
삽입 위치 지정 불가
insertAdjacentHTML(위치,HTML문자열) 기존 요소 유지 위치 지정해서 요소 삽입

=> 둘다, XSS(크로스 사이트 스크립팅 공격)에 취약 =>마크업 파싱하기 때문

doxument.getElementById() document.createElement('li') document.createTextNode() $li.appendChild()

노드를 생성하면, 독립적으로 존재하는 상태이기 때문에 기존 DOM에 추가하는 과정이 필요하다

 

노드를 추가하는 방법

(1) 요소 노드에 자식 노드가 있는 경우

(2) 요소 노드에 자식 노드가 없는 경우

 

기존 DOM에 추가될 때 DOM이 변경되기 때문에 리플로우와 리페인트가 실행된다.

따라서, for문을 통해 요소를 기존 DOM에 n번 추가하는 경우 n번의 리플로우 리페인트가 실행

 

컨테이너 요소 활용: 기촌 DOM에 한번만 자식 노드들을 모두 추가하기 위해

div 컨테이너 노드 document.createElement('div') 불필요한 컨테이너 요소 div가 DOM에 추가됨
DocumentFragment 컨테이너 노드 document.createDocumentFragment(); DOM에 컨테이너가 추가될 때, 컨테이너인 자신은 제거되고, 자신의 자식 노드만 DOM에 추가된다.

왜 노드를 자식의 자식 노드, 자식노드, DOM에 추가 하는 순서로 하는걸까? 생각했는데, 리렌더링이 일어나는 조건을 적게 일어나게 하기 위한게 아닐까(리플로우와 리페인트)

 

Node(부모의 부모노드)

노드 삽입 Node.prototype.insertBefore(nowNode, childNode) 첫번째 인수(자식 노드가 됨)
두번째 인수(부모 노드가 됨)
*두번째 인수 노드의 마지막 자식 요소 에 삽입
노드 이동 Node.prototype.insertBefore(nowNode, childNode) 이미 노드가 존재한다면
( const [ $first, $second, ] = $parentNode.children )
첫번째 인수의 노드를 제거하고,
두번째 인수 자식 노드 위치에 노드를 추가한다.
노드 복사 Node.prototype.cloneNode([deep: true | false]) true: 노드를 깊은 복사(모든 자손 노드 포함한 사본)
false: 노드를 얕은 복사(자신만의 사본. 자손 노드 불포함)
노드 교체 Node.prototype.replaceChild(newChild, oldChild) 호출한 노드의 자식 노드를 교체
old노드는  DOM에서 제거
노드 삭제 Node.prototype.removeChild(child) 매개변수로 전달한 노드를 DOM에서 삭제

어트리뷰트 노드는 attributes 프로퍼티로 얻을 수 있다(NamedNodeMap 객체를 반환)

const { attributes } = document.getElementById('user')
attributes.id.value
attributes.type.value
attributes.value.value
attributes 프로퍼티 getter로 값 취득만 가능
어트리뷰트 값을 참조 할 때 사용
Element.prototype.getAttribute(attributeName) attributes 프로퍼티를 통하지 않는다
직접 HTML 어트리뷰트 값을 취득
'문자열'로 입력
Element.prototype.setAttribute(attributeName, attributeValue) attributes 프로퍼티를 통하지 않는다
직접 HTML 어트리뷰트 값을 변경
'문자열'로 입력
초기 상태값을 변경
Element.prototype.hasAttribute(attributeName) HTML 어트리뷰트 존재 여부 확인
'문자열'로 입력
Element.prototype.removeAttribute(attributeName) 특정 HTML 어트리뷰트 삭제
'문자열'로 입력

● HTML 어트리뷰트에 대응하는 DOM 프로퍼티가 존재. 왜 각각 존재하는 걸까? => 요소노드는 상태(state)를 갖고있다!

HTML 어트리뷰트 HTML 요소의 초기 상태 지정
불변
초기 상태를 갖는 이유: 처음 표시하는 경우 또는 새로고침
어트리뷰트 노드에서 관리
DOM 프로퍼티 최신 상태 관리: HTML 어트리뷰트에 대응하는 요소 노드의 DOM 프로퍼티가 관리
사용자 입력에 의한 상태변화

결국 같은 의미 → 00 어트리뷰트, 00 프로퍼티

 

data 어트리뷰트와 dataset 프로퍼티

HTMLElement.prototype.style 프로퍼티 (setter/getter)

 

classList

add remove item contains replace toggle

 

요소에 적용되어있는 CSS 스타일 참조

의사 요소를 지정하는 문자열 전달 가능

 

DOM 표준: WHATWG


39.6 DOM 조작

새로운 노드를 생성하여 DOM에 추가, 기존 노드를 삭제 또는 교체

 

39.6.1 innerHTML

 (getter) 마크업이 포함된 문자열을 문자열 그대로 (변환없이) 반환

 (setter) 요소 노드의 innerHTML 프로퍼티에 문자열을 할당하면 마크업이 파싱되어, 요소 노드의 자식 노드로  DOM에 반환

 DOMPurify 라이브러리 권장

DOMPurify.sanitize('<img  ... >')

 삽입 위치 지정 불가

 

39.6.2 insertAdjacentHTML 메서드

 

39.7 어트리뷰트

39.7.1 어트리뷰트 노드와 attributes 프로퍼티

HTML 어트리뷰트 당 하나의 어트리뷰트 노드가 생성

<input id='user' type='text' value='hello'>

=> 3개의 어트리뷰트 노드가 생성

 

39.7.2 HTML 어트리뷰트 조작

 

39.7.3 HTML 어트리뷰트 vs DOM 프로퍼티

HTML 어트리뷰트에 대응하는 DOM 프로퍼티

DOM 프로퍼티는 참조와 변경이 가능

 

39.7.4 data 어트리뷰트와 dataset 프로퍼티

 

39.8 스타일

인라인 스타일 조작

HTMLElement.prototype.style 프로퍼티 (setter/getter)

 

39.8.2 클래스 조작

Element.prototype.className (setter/getter)

Element.prototype.classList: class 어트리뷰트의 정보를 담은 객체 반환

 

39.8.3 요소에 적용되어있는 CSS 스타일 참조

의사 요소를 지정하는 문자열 전달 가능

getComputedStyle( $class, ':before' );