[240520] 39장 DOM (3)
6. DOM 조작
- DOM 조작은 DOM 에 새로운 노드를 추가, 삭제, 교체하는 것을 말함
- DOM 에 변화가 생기면 리플로우와 리페인트가 발생한다.
- DOM 성능 최적화를 위해 주의해서 다루어야 함
1. innerHTML
- Element.prototype.innerHTML
- 요소 노드의 HTML 마크업을 취득하거나 변경함
- 요소노드의 콘텐츠 영역 (시작태그와 종료 태그 사이) 내에 포함된 모든 HTML 마크업을 문자열로 반환
- innderHTML 프로퍼티에 문자열을 할당하면 요소 노드의 모든 자식 노드가 제거되고 할당한 문자열에 포함되어 있는 HTML 마크업이 파싱되어 DOM 에 반영
// 노드 추가
$fruits.innerHTML += '<li>Banana</li>';
// 노드 교체
$fruits.innerHTML = '<li>Banana</li>';
// 노드 삭제
$fruits.innerHTML = '';
- 입력 받은 데이터를 innerHTML 프로퍼티에 할당하는 것은 크로스 사이트 스트립팅 공격에 취약하므로 위험하다.
- HTML5 에는 innerHTML 프로퍼티로 삽입된 script 요소는 실행하지 않는다.
- DOMPurify 라이브러리의 sanitize 사용 권장 (공격 예방)
- 삽입할때 추가하는거만 그리는게 아니라 자식 요소 다 새로 그리는거임
- 삽입될 위치 지정할 수 없음
2. insertAdjacentHTML 메서드
- Element.prototype.insertAdjacentHTML(position, DOMString)
-
기존 요소 제거하지 않으면서 위치를 지정해 새로운 요소 삽입
- 크로스 사이트 스크립팅 공격에 취약
3. 노드 생성과 추가
const $fruits = document.getElementById('fruits');
// 1. 요소 노드 생성
const $li = document.createElement('li');
// 2. 텍스트 노드 생성
const textNode = document.createTextNode('Banana');
// 3. 텍스트 노드를 $li 요소 노드의 자식 노드로 추가
$li.appendChild(textNode);
// 4. $li 요소 노드를 #fruits 요소 노드의 마지막 자식 노드로 추가
$fruits.appendChild($li);
4. 복수의 노드 생성과 추가
- foreach 로 DOM 에 매번 추가하면 리플로우와 리페인트가 매번 실행된다.
- 가급적 줄이는 편이 좋기 때문에, 자식 요소에 새로운 요소를 추가하고 마지막에 DOM 에 적용하는 것이 좋다.
- 이때, DocumentFragment 노드를 활용하면 좋다.
- DOM 에 추가하면 자신은 제거되고 자신의 자식 노드만 DOM 에 추가되기 때문
5. 노드 삽입
- 마지막 노드로 추가
- Node.prototype.appendChild 메서드는 인수로 전달 받은 노드를 자신을 호출한 노드 마지막 자식 노드 DOM 에 추가함, 위치 지정 X
- 지정한 위치에 노드 삽입
- Node.prototype.insertBefore(newNode, childNode)
- 첫번째 인수로 전달 받은 노드를 두 번째 인수로 전달 받은 노드 앞에 삽입한다.
- 두 번째 인수는 자식 노드여야하며 아니면 DOMException 에러 발생
6. 노드 이동
- appendChild, insertBefore 메서드 사용
7. 노드 복사
-
Node.prototype.cloneNode([deep: true false]) - true 면 깊은 복사, 자손 노드가 포함된 사본 생성
- 얕은 복사 자신만의 사본으로 생성
8. 노드 교체
- Node.prototype.replaceChild(newChild, oldChild)
- 첫 번째 매개변수 : 새로운 노드
- 두 번째 매개변수 : 교체될 노드
9. 노드 삭제
- Node.prototype.removeChild(child)
- 자식 노드여야함
어트리뷰트
1. 어트리뷰트 노드와 attributes 프로퍼티
- 글로벌 어트리뷰트 ( id, class, style, title, lang, .. )
- 이벤트 핸들러 어트리뷰트 (onclick, onchange .. )
- 어트리뷰트당 하나의 어트리뷰트 노드 생성
- 모든 어트리뷰트 노드의 참조는 유사 배열 객체이자 이터러블인 NamedNodeMap 객체에 담겨서 요소 노드의 attributes 프로퍼티에 저장된다.
- getter 만 존재 ( 읽기 전용 )
2. HTML 어트리뷰트 조작
- Element.prototype.getAttribute/setAttribute
- Element.prototype.hasAttribute
- Element.prototype.removeAttribute
3. HTML 어트리뷰트 vs DOM 프로퍼티
- DOM 프로퍼티들은 HTML 어트리뷰트 값을 초기값으로 가지고 있다.
- HTML 어트리뷰트는 DOM 에서 중복 관리되는 것처럼 보임
- 요소 노드의 attributes 프로퍼티에서 관리하는 어트리뷰트 노드
- HTML 어트리뷰트에 대응하는 요소 노드의 프로퍼티 (DOM 프로퍼티)
→ 중복X , HTML 어트리뷰트의 역할은 HTML 요소의 초기 상태를 지정하는 것이다.
어트리뷰트 노드
- 초기상태 관리
- 사용자의 입력에 의해 상태가 변경되어도 변하지 않음
- getAttribute/setAttribute 메서드를 사용하면 변경 가능
DOM 프로퍼티
- 사용자가 입력한 최신 상태는 요소노드의 DOM 프로퍼티가 관리
- 언제나 최신상태 유지
- 입력에 관한거만 최신 상태 값 관리, 외에는 상관없이 어트리뷰트와 DOM 프로퍼티는 항상 동일한 값으로 연동
HTML 어트리뷰트와 DOM 프로퍼티의 대응 관계
- 대부분 이름과 도일하게 1:1 대응
- 몇개는 다른거 있음
DOM 프로퍼티 값의 타입
- getArribute 메서드로 취득하면 언제나 문자열인데 DOM 은 아닐수도 있음 ( checked 이런거 )
4. data 어트리뷰트와 dataset 프로퍼티
- 접두사에 data- 이름을 사용하면 사용자 정의 어트리뷰트와 자바스크립트간에 데이터 교환 가능
- HTMLElement.dataset 프로퍼티로 취득 가능
- 어트리뷰트 정보를 제공하는 DOMStringMap 객체는 카멜 케이스로 변환해서 프로퍼티 갖고 있음
스타일
1. 인라인 스타일 조작
- HTMLElement.prototype.style
- setter, getter 로 인라인 스타일 추가나 변경 가능
- CSSStyleDeclaration 타입의 객체 반환
- 다양한 CSS 프로퍼티 갖고 있음
- 카멜 케이스 따름
2. 클래스 조작
- class 어트리뷰트에 대응하는 DOM 프로퍼티는 className, classList 다
- className 프로퍼티
- setter , getter 존재
- class 어트리뷰트 값 취득하거나 변경
- 문자열로 반환하고 문자열로 할당
- 공백으로 구분된 여러 개의 클래스 반환하기 어려움
- classList 프로퍼티
- class 어트리뷰트의 정보를 담은 DOMTokenList 객체 반환
- 유사 배열 객체면서 이터러블이다.
- forEach, entries, keys, values, supports 메서드 제공
$box.classList.add('foo') $box.classList.remove('foo') $box.classList.item(0) // box $box.classList.contains('foo') // true , false $box.classList.replace('foo', 'blue') $box.classList.toggle('foo') // 존재하면 제거, 존재하지 않으면 추가
- class 어트리뷰트의 정보를 담은 DOMTokenList 객체 반환
3. 요소에 적용되어 있는 CSS 스타일 참조
- style 프로퍼티는 인라인 스타일만 반환해서, 클래스나 상속을 통한 스타일은 참조할 수 없다.
- getComputedStyle 메서드 사용해야함
// box 요소에 적용된 모든 CSS 스타일 담고 있는 CSSStyleDeclaration 객체 획득
const computedStype = window.getComputedStyle($box);
Leave a comment