CH 39. DOM
DOM?
HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API(프로퍼티와 메서드)를 제공하는 트리 자료구조
39.1 노드
39.1.1 HTML 요소와 노드 객체
- HTML 요소는 HTML 문서를 구성하는 개별적인 요소를 의미함
- HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환됨
- HTML 요소의 어트리뷰트는 노드로, HTML 요소의 텍스트 콘텐츠는 텍스트 노드로 변환됨
39.1.2 노트 객체의 타입
문서노드, 요소노드, 어트리뷰트 노드, 텍스트 노드
예시) 다음 HTML 문서를 렌더링 엔진이 파싱 -- DOM 트리 생성
39.1.3 노드 객체의 상속 구조
- DOM은 HTML 문서의 계층적 구조와 정보를 표현
- 노드 타입에 따라 필요한 기능을 프로퍼티와 메서드의 집합인 DOM API로 제공
- DOM이 제공하는 프로퍼티와 메서드를 사용하여 노드에 접근하고
HTML의 구조나 내용 또는 스타일 등을 동적으로 변경하는 방법을 익히는 것이 중요함
39.2 요소 노드 취득
39.2.1 id를 이용한 요소 노드 취득
- getElementById 메서드 (Document.prototype의 프로퍼티)
- 반드시 문서 노드인 document를 통해 호출
- id 값은 HTML 문서 내 유일한 값이어야 함
- class 어트리뷰트와는 달리 공백 문자로 구분하여 여러 개의 값을 가질 수 없음
: 중복된 id 값을 갖는 요소가 여러 개 존재해도 에러는 발생하지 않음 (첫 번째 요소만 반환)
- 만약 인수로 전달된 id 값을 갖는 요소가 존재하지 않을 경우 null 반환
- 단, id 값과 동일한 이름의 전역 변수가 이미 선언되어 있으면, 이 전역 변수에 노드 객체가 재할당되지 않음
39.2.2 태그 이름을 이용한 요소 노드 취득
- getElementByTagName (Document.prototype, Element.prototype)
: Document.prototype - DOM 전체에서 요소 노드를 탐색해 반환
: Element.prototype - 특정 요소 노드의 자손 노드 중에서 요소 노드를 탐색해 반환
- 인수로 전달된 태그 이름을 갖는 요소가 존재하지 않는 경우 빈 객체를 반환
39.2.3 class를 이용한 요소 노드 취득
- class 어트리뷰트 값을 갖는 모든 요소 노드들을 탐색해 반환
- 인수로 전달할 class 값은 공백으로 구분하여 여러 개의 class를 지정할 수 있음
- 인수로 전달된 class 값을 갖는 요소가 존재하지 않는 경우 빈 객체를 반환
39.2.4 CSS 선택자를 이용한 요소 노드 취득
- CSS 선택자
전체 선택자 | 모든 요소를 선택 | * {...} |
태그 선택자 | 모든 p태그 요소를 모두 선택 | p {...} |
id 선택자 | id 값이 'foo'인 요소를 모두 선택 | #foo {...} |
class 선택자 | class값이 'foo'인 요소를 모두 선택 | .foo {...} |
어트리뷰트 선택자 | input요소 중에 type 어트리뷰트 값이 'text'인 요소를 모두 선택 |
input[type=text] {...} |
후손 선택자 | div요소의 후손 요소 중 p 요소를 모두 선택 | div p {...} |
자식 선택자 | div요소의 자손 요소 중 p 요소를 모두 선택 | div > p {...} |
인접 형제 선택자 | p요소의 형제 요소 중 p 요소 바로 뒤에 위치하는 ul 요소 선택 |
p + ul {...} |
일반 형제 선택자 | p요소의 형제 요소 중 p 요소 뒤에 위치하는 ul 요소를 모두 선택 |
p ~ ul {...} |
가상 클래스 선택자 | hover 상태인 a 요소를 모두 선택 | a:hover {...} |
가상 요소 선택자 | p 요소의 콘텐츠의 앞에 위치하는 공간을 선택 일반적으로 content 프로퍼티와 함께 사용됨 |
p::before {...} |
- querySelector 메서드는 인수로 전달한 CSS 선택자를 만족시키는 하나의 요소 노드를 탐색하여 반환
: 여러 개인 경우 첫 번째 요소만
: 존재하지 않을 경우 null
: 문법에 맞지 않는 경우 DOMException
- querySelectorAll은 만족시키는 모든 요소 노드를 반환
: 존재하지 않는 경우 빈 NodeList 객체 반환
- HTML 문서의 모든 요소 노드를 취득하려면 querySelectorAll의 인수로 전체 선택자'*'를 전달
- CSS 선택자 문법을 사용하는 메서드는 getElementById 메서드보다 다소 느림
: id 어트리뷰트가 있는 요소를 취득하는 경우에는 getElementById 메서드를 사용하고
그 외에는 querySelector 사용 권장
39.2.5 특정 요소 노드를 취득할 수 있는지 확인
- matches 메서드
: CSS 선택자를 통해 특정 요소 노드를 취득할 수 있는지 확인함
39.2.6 HTMLCollection과 NodeList
- 유사 배열 객체이면서 이터러블
: for 순회 가능, 스프레드 문법 사용
HTMLCollection
- 상태 변화를 실시간으로 반영하는 살아있는 객체
- for 문으로 순회하면서 노드 객체의 상태를 변경할 때 주의
: 이 문제는 for문을 역방향으로 사용하거나 while 사용하여 회피
NodeList
- HTMLCollection 부작용을 해결하기 위해 querySelectorAll 메서드 사용
: 이때 NodeList 객체는 실시간으로 노드 객체의 상태 변경을 반영하지 않는 객체
39.3 노드 탐색
39.3.1 공백 텍스트 노드
- HTML 요소 사이의 스페이스, 탭, 줄바꿈 등의 공백 문자는 공백 텍스트 노드를 생성
39.2.3 자식 노드 탐색
- 자식 노드를 탐색하는 노드 탐색 프로퍼티
39.3.3 자식 노드 존재 확인
- Node.prototype.hasChildNodes 메서드 사용 (텍스트 노드를 포함해 확인: true/false 반환)
- 텍스트 노드가 아닌 요소 노드가 존재하는지 확인하려면
: children.length 또는 Element 인터페이스의 childElementCount 프로퍼티 사용
39.3.4 요소 노드의 텍스트 노드 탐색
- firstChild 프로퍼티로 접근 가능
39.3.5 부모 노드 탐색
- Node.prototype.parentNode 프로퍼티를 사용함
- 텍스트 노드는 DOM 트리에서 리프 노드이므로, 부모 노드가 텍스트 노드인 경우는 없음
39.3.6 형제 노드 탐색
39.4 노드 정보 취득
39.5 요소 노드의 텍스트 조작
39.5.1 nodeValue
- setter, getter 모두 존재하는 접근자 프로퍼티
: nodeValue는 참조와 할당이 모두 가능함
- 요소 노드의 텍스트를 변경하는 순서
1. 텍스트를 변경할 요소 취득 -> 취득한 요소 노드의 텍스트 노드를 탐색 (firstChild 프로퍼티 사용해 탐색)
2. 탐색한 노드의 nodeValue 프로퍼티를 사용하여 텍스트 노드의 값을 변경
39.5.2 textContent
- setter, getter 모두 존재하는 접근자 프로퍼티
- 요소 노드의 텍스트와 모든 자손 노드의 텍스트를 모두 취득하거나 변경
- 취득 시 HTML 마크업은 무시
39.6 DOM 조작
- 새로운 노드를 생성하여 DOM에 추가하거나 기존 노드를 삭제 또는 교체하는 것
- 리플로우와 리페인트가 발생하는 원인이 되므로 성능에 영향을 줌 -> 주의해서 다뤄야 함
39.6.1 innerHTML
- textContent 프로퍼티를 참조하면 HTML 마크업을 무시하고 텍스트만 반환하지만,
innerHTML 프로퍼티는 HTML 마크업이 포함된 문자열을 그대로 반환함
// "Hello <span>world!</span>"
- 복잡하지 않은 요소를 새롭게 추가할 때 유용하지만
기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입해야 할 때는 사용하지 않는 것이 좋다.
39.6.2 insertAdjacentHTML 메서드
- 기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입함
- 두 번째 인수로 전달한 HTML 마크업 문자열을 파싱하고
그 결과로 생성된 노드를 첫 번째 인수로 전달한 위치에 삽입해 DOM에 반영
39.6.3 노드 생성과 추가
- DOM은 노드를 직접 생성/삽입/삭제/치환하는 메서드 제공
요소 노드 생성 | 요소 노드를 생성해 반환함. 매개변수: tagName | document.createElement('li'); |
텍스트 노드 생성 | 매개변수 text에는 텍스트 노드의 값으로 사용할 문자열 | document.createTextNode('Banana); |
텍스트 노드를 요소 노드의 자식 노드로 추가 | appendChild 메서드의 인수로 createTextNode 메서드로 생성한 텍스트 노드를 전달하면 마지막 자식 노드로 추가됨 |
$li.appendChild(textNode); |
요소 노드를 DOM에 추가 | 텍스트 노드와 부자 관계로 연결한 요소 노드를 마지막 자식요소로 추가 | $fruits.appendChild($li); |
39.6.4 복수의 노드 생성과 추가
- 여러 개의 요소 노드를 DOM에 추가하는 경우 DocumentFragment노드를 사용하는 것이 효율적임
39.6.5 노드 삽입
마지막 노드로 추가 | Node.prototype.appendChild 메서드는 인수로 전달받은 노드를 자신을 호출한 노드의 마지막 자식 노드로 DOM에 추가함. 이때, 위치 지정 불가능, 항상 마지막 자식 노드로 추가함 |
지정한 위치에 노드 삽입 | Node.prototype.insertBefore(newNode, childNode) 메서드는 첫 번째 인수로 전달받은 노드를 두 번째 인수로 전달받은 노드 앞에 삽입함. 두 번째 인수로 전달받은 노드는 반드시 insertBefore 메서드를 호출한 노드의 자식 노드이어야 함 |
39.6.6 노드 이동
- DOM 에 이미 존재하는 노드를 appendChild 또는 insertBefore 메서드를 사용하여 DOM에 다시 추가하면
현재 위치에서 노드를 제거하고 새로운 위치에 노드를 추가함 (노드 이동)
39.6.7 노드 복사
- Node.prototype.cloneNode([deep:true|false]) 메서드는 노드의 사본을 생성해 반환
- 매개변수 deep에 true르 인수로 전달하면 깊은 복사 (모든 자손 노드가 포함된 사본 생성)
- false 전달하거나 생략하면 얕은 복사 (노드 자신만의 사본을 생성)
39.6.8 노드 교체
- Node.prototype.replaceChild(newChild, oldChild) 메서드는 자신을 호출한 노드의 자식 노드를 다른 노드로 교체
- 첫 번째 매개변수 newChild에는 교체할 새로운 노드를 인수로 전달
- 두 번째 매개변수 oldChild에는 이미 존재하는 교체될 노드를 인수로 전달
39.6.9 노드 삭제
- Node.prototype.removeChild(child) 메서드는 child 매개변수에 인수로 전달한 노드를 DOM에서 삭제함
39.7 어트리뷰트
39.7.1 어트리뷰트 노드와 attributes 프로퍼티
- HTML 어트리뷰트 당 하나의 어트리뷰트 노드가 생성됨
- attributes 프로퍼티는 읽기 전용 접근자 프로퍼티로,
요소 노드의 모든 어트리뷰트 노드의 참조가 담긴 NamedNodeMap 객체를 반환함
39.7.2 HTML 어트리뷰트 조작
- attributes 프로퍼티는 읽기 전용이므로 값을 취득할 수는 있지만 변경은 할 수 없음
- Elment.prototype.getAttribute(attributeName)/setAttribute(attributeName, attributeValue)
메서드를 사용하면 직접 참조/변경 가능
39.7.3 HTML 어트리뷰트 vs. DOM 프로퍼티
- 요소 노드 객체에는 HTML 어트리뷰트에 대응하는 프로퍼티(DOM 프로퍼티)가 존재함
- 이 DOM 프로퍼티들은 HTML 어트리뷰트 값을 초기값으로 가지고 있음
- HTML 어트리뷰트의 역할?
: HTML 요소의 초기 상태를 지정하는 것
: HTML 어트리뷰트 값은 HTML 요소의 초기 상태를 의미하며 이는 변하지 않음
! 요소 노드는 초기 상태와 최신 상태를 가지고 있음- 요소 노드의 초기 상태는 어트리뷰트 노드가 관리하며, 요소 노드의 최신 상태는 DOM 프로퍼티가 관리함
HTML 어트리뷰트와 DOM 프로퍼티의 대응관계
- 대부분 1:1로 대응 (항상은 아님)1. id 어트리뷰트와 id 프로퍼티는 1:1 대응, 동일한 값으로 연동2. input 요소의 value 어트리뷰트는 value 프로퍼티와 1:1 대응 (value: 초기 상태, value프로퍼티: 최신 상태)3. class 어트리뷰트는 className, classList 프로퍼티와 대응4. for 어트리뷰트는 htmlFor 프로퍼티와 1:1 대응5. td 요소의 colspan 어트리뷰트는 대응하는 프로퍼티가 존재하지 않음6. textContent 프로퍼티는 대응하는 어트리뷰트가 존재하지 않음7. 어트리뷰트 이름은 대소문자를 구별하지 않지만, 대응하는 프로퍼티 키는 카멜 케이스를 따름
39.7.4 data 어트리뷰트와 dataset 프로퍼티
- HTML 요소에 정의한 사용자 정의 어트리뷰트와 자바스크립트 간에 데이터 교환 가능
- data 어트리뷰트의 값은 HTMLElement.dataset 프로퍼티로 취득할 수 있음
- dataset 프로퍼티는 HTML 요소의 모든 data 어트리뷰트의 정보를 제공하는 DOMStringMap 객체를 반환함
39.8 스타일
39.8.1 인라인 스타일 조작
- HTMLElement.prototype.style 프로퍼티는 접근자 프로퍼티로서 요소 노드의 인라인 스타일을 취득/추가/변경함
- 단위 지정이 필요한 CSS 프로퍼티 값은 반드시 단위를 지정해야 함
39.8.2 클래스 조작
- .으로 시작하는 클래스 선택자를 사용하여 CSS class를 미리 정의한 다음, HTML 요소의 스타일을 변경할 수 있음
className | - class 어트리뷰트 값을 문자열로 반환하고, 요소 노드의 className 프로퍼티에 문자열을 할당하면 class 어트리뷰트 값을 할당한 문자열로 변경함 - 문자열을 반환하므로 공백으로 구분된 여러 개의 클래스를 반환하는 경우 다루기 불편함 |
classList | - class 어트리뷰트의 정보를 담은 DOMTokenList 객체를 반환함 |
- DOMTokenList 객체는 유용한 메서드를 제공함
: add, remove, item, contains, replace, toggle, forEach, entries, keys, values, supports 등
39.8.3 요소에 적용되어 있는 CSS 스타일 참조
- HTML 요소에 적용되어 있는 모든 CSS 스타일을 참조해야 할 경우 getComputedStyle 메서드를 사용함
- 첫 번째 인수로 전달한 요소 노드에 적용되어 있는 평가된 스타일을 CSSStyleDeclaration 객체에 담아 반환함
- 평가된 스타일?
: 요소 노드에 적용되어 있는 모든 스타일이 조합되어 최종적으로 적용된 스타일
- 두 번째 인수로 :after, :before과 같은 의사 요소를 지정하는 문자열을 전달함
- 의사 요소가 아닌 일반 요소의 경우 두 번째 인수는 생략함
39.9 DOM 표준
'2022-2 웹개발 스터디' 카테고리의 다른 글
[모던 JS] CH37. Set과 Map, CH42. 비동기 프로그래밍 (1) | 2022.11.20 |
---|---|
[모던 JS] CH 34. 이터러블, CH 35. 스프레드 문법, CH 36. 디스트럭처링 할당 # 20 (0) | 2022.11.13 |
[모던 JS] CH 38. 브라우저의 렌더링 과정 (0) | 2022.11.12 |
[모던 JS] CH 32. String, CH33. 7번째 데이터 타입 Symbol (1) | 2022.11.08 |
[모던 JS] CH 28. Number, CH 29. Math, CH 30. Date, CH 31. RegExp (#16) (0) | 2022.11.05 |