Day 8DOM 기초

2주차는 브라우저다. 지금 보고 있는 이 페이지 자체가 DOM 트리이고, _system/components.jsberry-nav가 실제로 DOM을 조작해서 렌더링된다.

1. 요소 선택

document.querySelector(".proj-card")        // 첫 번째로 매칭되는 요소 (CSS 셀렉터 그대로)
document.querySelectorAll(".proj-card")      // 매칭되는 전체를 NodeList로 (배열은 아니지만 forEach는 됨)
document.getElementById("main")               // id로 하나만, querySelector보다 빠름

const cards = document.querySelectorAll(".proj-card");
cards.forEach((card) => console.log(card.textContent));

2. textContent vs innerHTML

사용자 입력이나 외부 데이터를 innerHTML에 그대로 넣으면 XSS(스크립트 삽입) 위험이 있다. 순수 텍스트만 넣을 땐 항상 textContent를 쓴다.
el.textContent = "안전한 텍스트";        // 태그로 해석 안 됨, 그대로 문자로 표시
el.innerHTML = "강조";              // 태그로 해석됨 — 신뢰할 수 있는 내용에만

3. 요소 생성과 삽입

const div = document.createElement("div");
div.className = "proj-card";
div.textContent = "새 카드";

container.append(div);          // 끝에 추가 (여러 개/문자열도 가능)
container.prepend(div);          // 앞에 추가
div.remove();                      // 자기 자신을 DOM에서 제거

// 속성 조작
div.classList.add("active");
div.classList.remove("active");
div.classList.toggle("active");
div.classList.contains("active")   // true/false
div.setAttribute("data-id", "42");
innerHTML += "..."를 반복 호출하면 매번 전체를 다시 파싱해서 느리다. 요소를 만들고 append로 붙이는 쪽이 정석이다.

🎯 실습 과제 — _submissions/day08.js

브라우저 없이도 코드로만 평가 가능하다 — 함수의 로직(어떤 DOM API를 어떤 순서로 호출하는지)이 핵심이다. 아래 데이터를 파일에 선언하고 시작.

const items = [
  { name: "algorithms", meta: "12개 문서" },
  { name: "rust-book", meta: "3개 폴더" },
  { name: "calculus", meta: "5개 문서" },
];

과제 1. 카드 렌더러
이 사이트의 .proj-card 그리드처럼, items 배열을 받아 각 항목마다 div.proj-card를 만들어 container에 추가하는 함수를 작성한다. 카드 안에는 span.card-name(name 텍스트)과 span.card-meta(meta 텍스트) 두 개의 자식 요소가 있어야 한다.

function renderCards(container, items) {
  // TODO: createElement + classList + append 조합으로 구현
}

과제 2. 비우고 다시 그리기
clearAndRender(container, items): 먼저 container 안의 기존 자식을 전부 지우고(innerHTML 초기화나 반복 remove), 그 다음 renderCards를 호출한다.

과제 3. 활성 카드 토글
toggleActive(container, name): container 안에서 card-name 텍스트가 name과 일치하는 카드를 찾아 "active" 클래스를 토글한다.

과제 4 (도전). 안전한 렌더링
renderCardsinnerHTML 대신 textContent/DOM API만 써서 구현했는지 스스로 점검하고, 왜 그게 더 안전한지 파일 맨 위에 주석 한 줄로 설명을 남긴다.

✅ 다 작성했으면:
cd ~/Documents/javascript-2주완성
bun _grade.ts day08