17. DOM 선택과 조회
브라우저는 HTML 을 파싱해 DOM(Document Object Model) 트리를 만듭니다. 자바스크립트는 이 트리를 읽고 수정해 화면을 바꿉니다.
이 강의에서 배우는 것
- 1DOM 트리의 개념을 이해한다.
- 2`querySelector`, `querySelectorAll`, `getElementById` 로 요소를 선택한다.
- 3`getAttribute`, `dataset` 으로 속성을 읽는다.
- 4`textContent` 와 `innerHTML` 의 차이(특히 XSS)를 안다.
- 5부모/자식/형제 노드를 탐색한다.
소개
브라우저는 HTML 을 파싱해 DOM(Document Object Model) 트리를 만듭니다. 자바스크립트는 이 트리를 읽고 수정해 화면을 바꿉니다.
핵심 개념
1. DOM 이란?
브라우저는 HTML 을 파싱해 DOM(Document Object Model) 트리를 만듭니다. 자바스크립트는 이 트리를 읽고 수정해 화면을 바꿉니다.
2. 요소 선택
const title = document.querySelector("#title"); // 첫 매칭
const items = document.querySelectorAll(".item"); // NodeList
const byId = document.getElementById("title");`querySelector` 는 CSS 선택자를 그대로 받습니다. `querySelectorAll` 은 정적인 NodeList 를 돌려주므로 forEach 가 가능합니다.
3. 속성 조회
const link = document.querySelector("a");
link.getAttribute("href");
link.href; // DOM 프로퍼티
link.dataset.userId; // data-user-id 속성4. textContent vs innerHTML
`textContent` 는 단순 텍스트로 읽고/쓰기 때문에 안전합니다. `innerHTML` 은 HTML 문자열을 파싱하므로 사용자 입력을 그대로 넣으면 XSS 공격에 노출됩니다. 외부 입력은 항상 `textContent` 또는 sanitize 후 사용합니다.
5. 트리 탐색
el.parentElement;
el.children;
el.firstElementChild;
el.nextElementSibling;핵심 예제
| 파일 | 다루는 내용 |
|---|---|
| index.html | 예제용 HTML 페이지 |
| 01_query_selector.js | querySelector/All 사용 |
| 02_attributes.js | getAttribute / dataset |
| 03_text_html.js | textContent vs innerHTML |
| 04_nested.js | 부모/자식/형제 탐색 |
src/01_query_selector.js
/**
* querySelector / querySelectorAll / getElementById 비교.
*/
const title = document.querySelector("#title");
console.log("title:", title.textContent);
const items = document.querySelectorAll(".item");
console.log("아이템 개수:", items.length);
items.forEach((el) => console.log("-", el.textContent));
const byId = document.getElementById("msg");
console.log("msg:", byId.textContent);
src/02_attributes.js
/**
* 속성과 dataset 읽기.
*/
const link = document.querySelector("#link");
console.log("href(attr):", link.getAttribute("href"));
console.log("href(prop):", link.href);
document.querySelectorAll(".item").forEach((el) => {
console.log("id =", el.dataset.id, ", text =", el.textContent);
});
src/03_text_html.js
/**
* textContent 와 innerHTML 의 차이.
* 사용자 입력을 innerHTML 에 그대로 넣으면 XSS 위험이 있습니다.
*/
const msg = document.querySelector("#msg");
console.log("textContent:", msg.textContent);
console.log("innerHTML:", msg.innerHTML);
msg.textContent = "<b>안전</b>";
console.log("이후 textContent:", msg.textContent);
src/04_nested.js
/**
* 부모/자식/형제 노드 탐색.
*/
const list = document.querySelector("#list");
console.log("자식 수:", list.children.length);
console.log("첫 자식:", list.firstElementChild.textContent);
console.log("두 번째 자식:", list.firstElementChild.nextElementSibling.textContent);
console.log("부모 태그:", list.parentElement.tagName);
src/index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>DOM 선택과 조회</title>
</head>
<body>
<h1 id="title">DOM 예제</h1>
<ul id="list">
<li class="item" data-id="1">사과</li>
<li class="item" data-id="2">바나나</li>
<li class="item" data-id="3">체리</li>
</ul>
<a href="https://example.com" id="link">예제 링크</a>
<p id="msg">Hello</p>
<script src="01_query_selector.js"></script>
<script src="02_attributes.js"></script>
<script src="03_text_html.js"></script>
<script src="04_nested.js"></script>
</body>
</html>
자주 하는 실수
- 스크립트를 `<head>` 에서 로드해 DOM 이 아직 없는 상태에서 접근.
- `querySelectorAll` 결과를 배열로 착각해 `.map` 직접 호출 (Array.from 필요).
- `innerHTML` 에 사용자 입력을 그대로 삽입.
- `getAttribute("class")` 와 `el.className` 의 미묘한 차이 무시.
- id 가 같은 요소가 여러 개일 때의 동작에 의존.
FAQ
Q1. getElementById 와 querySelector("#id") 중 무엇이 좋나요?
성능 차는 미미합니다. 일관성을 위해 querySelector 만 써도 됩니다.
Q2. NodeList 와 HTMLCollection 의 차이?
NodeList 는 정적(또는 라이브), HTMLCollection 은 항상 라이브이며 forEach 가 없습니다.
Q3. dataset 의 키 이름 규칙?
data-user-id 는 dataset.userId 로 카멜케이스 변환됩니다.
과제
HTML 페이지에서 특정 클래스의 모든 항목을 선택해 목록을 콘솔에 출력하세요.
homework/README.md
HTML 의 `.fruit` 항목들을 모두 선택해 다음을 출력하세요.
- 각 항목의 텍스트
- data-color 속성 값
답안은 `answer/homework_01.html` 과 `answer/homework_01.js` 를 참고하세요.
homework/answer/homework_01.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>과제 17-1</title>
</head>
<body>
<ul id="fruits">
<li class="fruit" data-color="red">사과</li>
<li class="fruit" data-color="yellow">바나나</li>
<li class="fruit" data-color="purple">포도</li>
</ul>
<script src="homework_01.js"></script>
</body>
</html>
homework/answer/homework_01.js
/**
* .fruit 요소들의 텍스트와 색상 속성을 출력합니다.
*/
const fruits = document.querySelectorAll(".fruit");
fruits.forEach((el) => {
console.log(`${el.textContent} -> ${el.dataset.color}`);
});
다음 단원
[18_DOM_조작](../18_DOM_조작/) — 요소 만들기/추가/삭제