본문 바로가기
Front-End/JavaScript

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

by kk님 2023. 5. 22.

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


DOM(Document Object Model): 노드 객체로 구성된 트리 자료구조

- 이를 제어할 수 있는 API, 즉 프로퍼티와 메서드를 제공하는 트리 자료구조

- DOM이 제공하는 프로퍼티와 메서드를 사용하여 노드에 접근, HTML의 구조와 내용 또는 스타일 등을 동적으로 변경하는 방법을 익히는 것이 중요

 

Element: Tag?

요소 노드 == 태그

 

중첩 관계 

비선형 자료구조: 하나의 자료 뒤에 여러 개의 자료가 존재할 수 있는 자료구조

 

DOM API를 통해

(1) 자신의 부모, 형제, 자식 탐색 가능

(2) 자신의 어트리뷰트와 텍스트를 조작 가능

 

live DOM 컬렉션 객체

: 실시간으로 노드 객체의 상태 변경을 반영하여 요소를 제거하기 때문에, 상태를 변경할 때 주의해야 한다.

 

해결방법

 [ ... $elements] 배열로 변환하기!

(혹은, for문을 역방향으로 순회함으로 회피가능)

 

비구조화 할당 활용하여 추출 가능

const $fruites = document.getElementById('fruits')
const {firstChild} = $fruits;

 

DOM은 파싱 이후 트리구조를 갖는다.

 

DOM API

(1) 어떤 노드를 탐색할 것인지

● 요소 노드 취득하는 방법: 태그 이름, class 이름, CSS 선택자

● 요소 노드를 취득할 수 있는지 true/false

 

(2) 반환된 요소 노드 리스트에서, (배열로 변환한 뒤 활용할 것!)

(3) 해당 노드의 부모 노드를? 형제 노드를? 자식 노드를? 탐색할 것인지

(4) 어트리뷰트 또는 텍스트를 조작할 것인지

● nodeValue

● textContent

 

탐색 시간에 따라, 어떤 프로퍼티를 사용할지 달라진다.


 

39.1 노드

39.1.1 HTML 요소와 노드 객체

HTML element: HTML 문서를 구성하는 개별적인 요소

HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환

어트리뷰트 → 어트리뷰트 노드

텍스트 콘텐츠 → 텍스트 노드

 

<div class = “greeting”>Hello</div>

중첩 관계 → 계층적인 부자 관계 형성(parent-child)

 

트리 자료구조

비선형 자료구조(하나의 자료 뒤에 여러 개의 자료가 존재할 수 있는 자료구조)

39.1.2 노드 객체의 타입

노드 타입

문서 노드 document 객체 DOM 트리 최상위 루트 노드
요소 노드 HTML 요소를 가리키는 객체 중첩에 의한 부자 관계
어트리뷰트 노드   요소 노드와 연결(단, 부모 노드는 없기 때문에 요소 노드의 형제 노드는 아님)
텍스트 노드   요소 노드의 자식노드
리프노드

39.1.3 노드 객체의 상속 구조

DOM API를 통해

(1) 자신의 부모, 형제, 자식 탐색 가능

(2) 자신의 어트리뷰트와 텍스트를 조작 가능

 

DOM을 구성하는 노드는 빌트인 객체가 아니라, 브라우저 환경에서 추가적으로 제공하는 호스트 객체

상속 구조

모든 노드 객체는 Object, EventTarget, Node 인터페이스를 상속받는다

 

Node 인터페이스를 상속받아 모든 노드 객체는 트리 탐색 기능, 노드 정보 제공 기능이 가능하다

 

공통된 기능일수록 프로토타입 체인 상위에 위치한다

개별 고유 기능일수록 프로토타입 체인 하위에 프로토타입 체인을 구축.

 

39.2 요소 노드 취득

동적으로 조작하기 위한 첫번째 방법

 

39.2.1 id를 이용한 요소 노드 취득

● id는 유일한 값

Document.prototype.getElementById

● id가 여러개라면 첫번째 요소 노드만 반환

 

39.2.2 태그 이름을 이용한 요소 노드 취득

 

getElementsByTagName 메서드

Elements => 복수형

만약, document.getElementsByTagName('*')을 하게 되면, HTML 문서의 모든 요소 노드를 취득 가능

 

Document.prototype.getElementsByTagName Element.prototype.getElementsByTagName
document 를 통해 호출
document.getElementsByTagName
DOM 전체에서 요소 노드를 탐색하여 반환
특정 노드를 통해 호출
$value.getElementsByTagName
특정 요소 노드의 자손 노드 중에서 노드를 탐색하여 반환

39.2.3 class를 이용한 요소 노드 취득

Document.prototype.getElementsByClassName

Element.prototype.getElementsByClassName

 

공백으로 구분하여 여러 개의 class 지정 가능

예시: Document.prototype.getElementsByClassName("fruit apple")

 

39.2.4 CSS 선택자를 이용한 요소 노드 취득

Document.prototype/Element.prototype.querySelector

Document.prototype/Element.prototype.querySelectorAll

 

★ CSS 선택자 문법은  getElementBy~ 메서드보다 느리다

따라서, id 어트리뷰트가 있는 요소 노드를 취득하는 경우는 getElementById 메서드를 사용하기

그 외의 경우는 quertSelector,querySelectorAll 사용하기

 

39.2.5 특정 요소 노드를 취득할 수 있는지 확인

Element.prototype.matches

이벤트 위임을 사용할 때

 

39.2.6 HTMLCollection과 NodeList

두 개념 모두 유사 객체 배열이면서 이터러블

for문으로 순회하며 요소 값을 변경

live DOM 컬렉션 객체

 

HTMLCollection

- getElementsByTagName가 반환

- getElementsByClassName가 반환

 

live DOM 컬렉션 객체

: 실시간으로 노드 객체의 상태 변경을 반영하여 요소를 제거하기 때문에, 상태를 변경할 때 주의해야 한다.

0번째 노드를 변경해서, 0번 인덱스 요소가 배열에서 삭제된다(popleft). 따라서, 1번 인덱스 요소가 0번 위치로 이동하기 때문에 아직 바뀌지 않은 0번 인덱스를 수정하지 않고 넘기는 것

 

(1) for문을 역방향으로 순회함으로 회피가능

(2) [ ... $elements] 배열로 변환하기. 고차 함수도 사용 가능하다

 

NodeList

querySelectorAll

non-live DOM 컬렉션 객체

과거의 정적 상태를 유지함

하지만, childNodes 프로퍼티가 반환하는 NodeList 객체는 live 객체로 동작

 

해결방법

 [ ... $elements] 배열로 변환하기!

 

39.3 노드 탐색

모두 (읽기 전용) 접근자 프로퍼티

 

39.3.1 공백 텍스트 노드

스페이스, 탭, 줄바꿈(개행)

 

39.3.2 자식 노드 탐색

Node.prototype.childNodes 자식 노드 모두 탐색
요소노드, 텍스트 노드
NodeList 반환
Element.prototype.children 자식 노드 중 요소 노드만 탐색
HTMLCollection에 담아 반환
Node.prototype.firstChild 첫번째 자식 노드 반환
요소노드 또는 텍스트 노드
Node.prototype.lastChild 마지막 자식 노드 반환
요소노드 또는 텍스트 노드
Element.prototype.firstElementChild 첫번째 자식 노드 반환
요소노드만 반환
Element.prototype.lastElementChild 마지막 자식 노드 반환
요소노드만 반환

 

39.3.3 자식 노드 존재 확인

Node.prototype.hasChildNodes

반환 값: true/false

(요소노드와 텍스트노드)

 

자식 노드 중 텍스트 노드가 아닌 노드가 존재하는지 확인

children.length 또는 childElementCount

 

39.3.4 요소 노드의 텍스트 노드 탐색

firstChild 프로퍼티

 

39.3.5 부모 노드 탐색

Node.prototype.parentNode

텍스트 노드가 반환되지 않는다.(선택한 노드의 부모 노드는 텍스트 노드가 될 수 없다)

 

39.3.6 형제 노드 탐색

Node.prototype.previousSibling

Node.prototype.nextSibling

Element.prototype.previousElementSibling

Element.prototype.nextElementSibling

 

const $fruites = document.getElementById('fruits')
const {firstChild} = $fruits;

39.4 노드 정보 취득

Node.prototype.nodeType

Node.prototype.nodeName

 

39.5 요소 노드의 텍스트 조작

39.5.1 nodeValue

setter/ getter

노드 객체의 값 반환.(텍스트 노드의 텍스트 반환)

=> 요소 노드의 경우 null을 반환

 

(1) 텍스트를 변경할 요소 노드 취득

(2) 취득한 요소 노드의 텍스트 노드 탐색

(3) 텍스트 노드는 요소 노드의 자식 노드이므로 fistChild 프로퍼티 사용하여 탐색

(4) 탐색한 텍스트 노드의 nodeValue 프로퍼티를 사용하여 텍스트 노드의 값 변경

 

39.5.2 textContent

요소 노드의 텍스트와 모든 자손 노드텍스트모두 취득하거나 변경

(1) 탐색의 경우

텍스트만 모두 반환(마크업 생략)

 

(2) 할당의 경우

자식 노드가 모두 제거되고, '문자열'이 텍스트로 추가된다(마크업이 포함되더라도, 문자열로 그대로 출력=마크업이 파싱되지 않는다)

 

nodeValue 보다 textContent를 사용하는 편이 더 간단한 것 같다.

 

innerText 프로퍼티를 사용하는 것이 좋지 않은 이유

- CSS에 순종적이기 때문에, visibility: hidden인 경우 지정된 요소 노드의 텍스트를 반환하지 않는다

- CSS를 고려해야 하므로 textContent 프로퍼티보다 느리다