2주차는 브라우저다. 지금 보고 있는 이 페이지 자체가 DOM 트리이고, _system/components.js의 berry-nav가 실제로 DOM을 조작해서 렌더링된다.
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));
innerHTML에 그대로 넣으면 XSS(스크립트 삽입) 위험이 있다. 순수 텍스트만 넣을 땐 항상 textContent를 쓴다.
el.textContent = "안전한 텍스트"; // 태그로 해석 안 됨, 그대로 문자로 표시
el.innerHTML = "강조"; // 태그로 해석됨 — 신뢰할 수 있는 내용에만
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 (도전). 안전한 렌더링
renderCards를 innerHTML 대신 textContent/DOM API만 써서 구현했는지 스스로 점검하고, 왜 그게 더 안전한지 파일 맨 위에 주석 한 줄로 설명을 남긴다.
cd ~/Documents/javascript-2주완성
bun _grade.ts day08