Files
2nd/10_Wiki/Topics/Programming & Language/DOM 요소 조작.md
T
2026-05-10 22:08:15 +09:00

5.9 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-dom-요소-조작 DOM 요소 조작 10_Wiki/Topics verified self
DOM Manipulation
Vanilla JS DOM
Document API
none A 0.9 applied
dom
javascript
web
browser
2026-05-10 pending
language framework
javascript dom

DOM 요소 조작

매 한 줄

"매 Document 의 tree 의 query + mutation 의 web 기본 API". 매 jQuery 의 era 종료, 2026 의 modern DOM (querySelector, classList, dataset, MutationObserver) 의 충분 + framework (React/Solid/Svelte) 의 abstraction 위. 매 vanilla 의 fast path + 매 small widget 의 right tool.

매 핵심

매 Query

  • getElementById(id) — 매 fastest single lookup.
  • querySelector(sel) / querySelectorAll(sel) — CSS selector general.
  • closest(sel) — 매 ancestor traversal.
  • matches(sel) — boolean check.

매 Mutate

  • Create: createElement, cloneNode(true), <template> + content.cloneNode.
  • Insert: append, prepend, before, after, replaceWith.
  • Remove: el.remove().
  • Attribute: setAttribute, dataset.x, classList.add/toggle/remove.
  • Content: textContent (safe) vs innerHTML (XSS risk).

매 Observe

  • MutationObserver — 매 subtree change.
  • IntersectionObserver — viewport visibility.
  • ResizeObserver — element size.

매 응용

  1. Lightweight widget (no framework) — banner, modal, tooltip.
  2. Server-rendered HTML enhancement (Hotwire, Astro islands).
  3. Browser extension content script.

💻 패턴

Element creation (template)

<template id="card-tpl">
  <article class="card">
    <h3 class="title"></h3>
    <p class="body"></p>
  </article>
</template>
function renderCard({ title, body }) {
  const tpl = document.getElementById('card-tpl');
  const node = tpl.content.cloneNode(true);
  node.querySelector('.title').textContent = title;
  node.querySelector('.body').textContent = body;
  return node;
}
document.querySelector('#list').append(renderCard({ title: 'Hi', body: 'World' }));

classList + dataset

const btn = document.querySelector('#toggle');
btn.classList.toggle('active');
btn.dataset.count = (Number(btn.dataset.count ?? 0) + 1).toString();
// HTML: <button id="toggle" data-count="3">

Event delegation

document.addEventListener('click', (e) => {
  const action = e.target.closest('[data-action]');
  if (!action) return;
  switch (action.dataset.action) {
    case 'open': openModal(action.dataset.id); break;
    case 'delete': remove(action.dataset.id); break;
  }
});

Safe insertion (avoid innerHTML)

// 매 X — XSS
container.innerHTML = `<p>${userInput}</p>`;

// 매 O — textContent
const p = document.createElement('p');
p.textContent = userInput;
container.append(p);

// 매 trusted HTML 만 — Sanitizer API (2026 baseline)
container.setHTML(trustedString);   // 의 native sanitize

IntersectionObserver — lazy load

const io = new IntersectionObserver((entries) => {
  for (const e of entries) {
    if (!e.isIntersecting) continue;
    const img = e.target;
    img.src = img.dataset.src;
    io.unobserve(img);
  }
});
document.querySelectorAll('img[data-src]').forEach((img) => io.observe(img));

MutationObserver — react to subtree

const mo = new MutationObserver((muts) => {
  for (const m of muts) {
    for (const n of m.addedNodes) {
      if (n instanceof HTMLAnchorElement) enhanceLink(n);
    }
  }
});
mo.observe(document.body, { childList: true, subtree: true });

Form serialization

const form = document.querySelector('#login');
form.addEventListener('submit', (e) => {
  e.preventDefault();
  const data = Object.fromEntries(new FormData(form));
  fetch('/login', { method: 'POST', body: JSON.stringify(data), headers: { 'Content-Type': 'application/json' } });
});

Animation — Web Animations API

el.animate(
  [{ opacity: 0, transform: 'translateY(10px)' }, { opacity: 1, transform: 'none' }],
  { duration: 200, easing: 'ease-out', fill: 'forwards' },
);

Batched DOM updates

const frag = document.createDocumentFragment();
for (const item of items) frag.append(renderRow(item));
list.append(frag);   // 매 single reflow

매 결정 기준

상황 Approach
Static + small interaction Vanilla DOM
100s of components React / Solid / Svelte
Server HTML + enhancement Hotwire / Astro
Lazy load images IntersectionObserver
External widget injection MutationObserver
Animation Web Animations API

기본값: querySelector + classList + textContent + delegation + Observer APIs.

🔗 Graph

  • 부모: DOM · Web_APIs
  • 변형: DOM_요소_조작_및_타입_좁히기 · Shadow_DOM
  • 응용: Web_Components · Browser_Extensions · Hotwire
  • Adjacent: IntersectionObserver · MutationObserver · Sanitizer_API

🤖 LLM 활용

언제: vanilla widget scaffold, Observer setup, jQuery → modern migration. 언제 X: 매 framework app — 매 framework primitive 의 사용.

안티패턴

  • innerHTML with user input: 매 XSS — textContent 또는 Sanitizer.
  • Loop append in DOM: 매 N reflows — DocumentFragment 의 사용.
  • No event delegation: 1000 listener 의 memory + perf 비용.
  • document.write: deprecated — 매 stream block.
  • Manual style mutation everywhere: classList toggle + CSS 의 사용.

🧪 검증 / 중복

  • Verified (MDN DOM, Web Animations, Observers, Sanitizer API spec).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — query/mutate/observe patterns + Sanitizer + delegation