JavaScript | DOM 操作:ノード操作 – fragment の利用

JavaScript
スポンサーリンク

DocumentFragment とは何か

DocumentFragment(以下フラグメント)は、DOM に一時的に要素を“まとめて保持するための入れ物”です。画面(実DOM)にまだ接続されていないミニDOMと考えてください。ここが重要です:フラグメントに大量の要素を作ってから“一度で”親へ挿入すると、描画やレイアウト再計算が最小化され、体感が大幅に軽くなります。


基本の作り方と挿入(まとめて作って一度で挿す)

フラグメントを作り、子要素をためてから挿入

const frag = document.createDocumentFragment(); // 空のフラグメントを作成

for (let i = 1; i <= 100; i++) {
  const li = document.createElement("li");
  li.textContent = `項目 ${i}`;
  frag.appendChild(li); // 実DOMに影響せず、フラグメントに溜める
}

// 100個分を一度に挿入(ここで初めて画面に)
document.getElementById("list").appendChild(frag);
JavaScript

ここが重要です:一件ごとに実DOMへ追加すると、その度にスタイル計算・レイアウトが走ります。フラグメントにためる → 一括挿入で、再計算が“1回”になり高速です。


性能の考え方(読む→書くを分け、バッチ更新で軽くする)

読み取りと書き込みを分離する

DOM からサイズやスタイルを“読む処理”を先にまとめて行い、その後でフラグメントに“書く処理(生成・追加)”をまとめて行います。ここが重要です:読み→書き→読み→書き…と交互にすると、レイアウトスラッシングが起きて重くなります。読みのブロック、書きのブロックに分けるだけで、パフォーマンスが安定します。


appendChild や insertBefore と組み合わせる(任意位置へ一括挿入)

参照要素の“前”にまとめて入れる

const ref = document.querySelector("#list .marker");
const frag = document.createDocumentFragment();
["A", "B", "C"].forEach(t => {
  const li = document.createElement("li");
  li.textContent = t;
  frag.appendChild(li);
});
ref.parentNode.insertBefore(frag, ref); // marker の直前に A,B,C を一括挿入
JavaScript

ここが重要です:フラグメントは“親子関係を持てる”ので、insertBefore の newNode として渡すだけで、内容がそのまま展開されます(フラグメント自身は挿入後に空になり消える仕様です)。


template とフラグメント(雛形の複製と安全な差し込み)

<template> は中身がフラグメント(描画されない雛形)

<template id="tpl-card">
  <article class="card">
    <h3 class="title"></h3>
    <p class="desc"></p>
    <button class="buy">購入</button>
  </article>
</template>
<div id="root"></div>
<script>
  function render(item) {
    // template.content は DocumentFragment
    const node = document.getElementById("tpl-card").content.cloneNode(true);
    node.querySelector(".title").textContent = item.title;
    node.querySelector(".desc").textContent = item.desc;
    node.querySelector(".buy").addEventListener("click", () => alert("購入"));
    document.getElementById("root").appendChild(node); // 一括で展開され挿入
  }
  render({ title: "りんご", desc: "甘いです" });
</script>
HTML

ここが重要です:template.content は最初からフラグメントとして提供され、cloneNode(true) で安全・高速に複製できます。ユーザー入力は textContent で差し込み、innerHTML の乱用を避けると安全性が高まります。


よくある落とし穴と対策(イベント、id 重複、状態の引き継ぎ)

フラグメントに入れてもイベントは“追加した要素に付く”

フラグメント内で addEventListener したイベントは、後で実DOMへ挿入してもそのまま動作します。ここが重要です:フラグメントは“仮置き場”ですが、ノード自体は本物。挿入後もイベントや属性は維持されます。

id の重複に注意

複製して大量挿入する場合、id が重複すると参照が壊れます。ここが重要です:clone 後に id を一意に付け替える、またはテンプレート側では id を持たせず、必要な要素は class/データ属性で参照する方針にします。

動的状態の再設定

input の value、checkbox の checked、video の currentTime など“現在状態”は複製・生成時の初期値になりがちです。ここが重要です:挿入前に必要な状態を明示的に再設定し、期待通りの見え方・挙動にします。


実践例(大量リスト生成、差し替え、セクション一括更新)

大量リストを一括生成して挿入

const root = document.getElementById("list");
const frag = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  const li = document.createElement("li");
  li.textContent = `ログ #${i}`;
  frag.appendChild(li);
}
root.appendChild(frag); // 1000件でも“1回の挿入”
JavaScript

ここが重要です:大量でもサクっと挿入でき、スクロール領域の初期描画が快適になります。さらに最適化したい場合は仮想リスト(可視範囲のみ生成)も検討します。

部分差し替え(古い子を全消し→新内容をフラグメントで挿入)

const box = document.getElementById("box");
const frag = document.createDocumentFragment();
["概要", "詳細", "注記"].forEach(text => {
  const p = document.createElement("p");
  p.textContent = text;
  frag.appendChild(p);
});
box.replaceChildren(frag); // クリアしてフラグメントの中身を一撃で挿入
JavaScript

ここが重要です:replaceChildren は“全消し+まとめて追加”を一回で。フラグメントと組み合わせると読みやすさ・性能が両立します。

ヘッダ直下にまとめて挿入(位置指定+フラグメント)

const header = document.querySelector("header");
const frag = document.createDocumentFragment();

const nav = document.createElement("nav");
nav.textContent = "ナビ";
const note = document.createElement("div");
note.className = "note";
note.textContent = "お知らせ";

frag.append(nav, note); // append は複数引数OK
header.insertBefore(frag, header.firstChild); // 先頭に一括で
JavaScript

ここが重要です:位置の制御(先頭・直前直後)とフラグメントの“まとめ”を組み合わせれば、レイアウトの乱れが少なく、意図した場所に素直に入れられます。


まとめ

DocumentFragment は「多数のノードをまとめて用意して、一度で挿入」できる仮DOMの入れ物です。createDocumentFragment → 子を作ってためる → append/insertBefore/replaceChildren で一括挿入、という型を使うと、描画・レイアウトの再計算が最小化されて高速になります。template.content(フラグメント)との組み合わせで安全な雛形複製ができ、イベントは複製後に付けても挿入後まで生きます。id 重複や動的状態の再設定に注意し、読みと書きの分離で更に軽くする。この流れを身につければ、初心者でも大規模な DOM 生成・差し替えを快適に扱えます。

タイトルとURLをコピーしました