JavaScript | Web API:DOM 拡張 API - documentFragment

JavaScript JavaScript
スポンサーリンク

documentFragment は「画面にまだ挿していない一時作業用のミニ DOM」

DocumentFragmentdocument.createDocumentFragment() で作るやつ)は、
「まだ画面には存在しないけれど、DOM を組み立てておける一時的な箱」 です。

普通は、要素を 1 個ずつ appendChild すると、そのたびに画面が更新されます。
大量の要素を追加するとき、それはパフォーマンス的にちょっと重い。

そこで一度、画面の外(=DocumentFragment)でまとめて DOM を組み立ててから、
最後に親要素に「ドンッ」と一括で挿し込む——
これが DocumentFragment の典型的な使い方です。

イメージとしては「作業台でまとめて部品を組み立ててから、本体に取り付ける」感じです。


基本:document.createDocumentFragment() で「作業用の箱」を作る

一番シンプルな流れ

const frag = document.createDocumentFragment();

// ここに要素をどんどん追加していく
const p1 = document.createElement("p");
p1.textContent = "一つ目";

const p2 = document.createElement("p");
p2.textContent = "二つ目";

frag.appendChild(p1);
frag.appendChild(p2);

// 最後にまとめて本物の DOM に挿す
const container = document.querySelector("#container");
container.appendChild(frag);
JavaScript

ここで重要なのは、
frag 自体は画面に表示されない「見えないコンテナ」だということです。

frag に追加した要素は、
container.appendChild(frag) した瞬間に、
frag の中身だけが container に移動します(frag は空になる)。

なぜわざわざ fragment を使うのか

理由はシンプルで、

画面の DOM を何度も書き換えるより
一度にまとめて挿したほうが、無駄な再描画が減るから

です。

小さい規模では違いは分かりにくいですが、
「1000 個の要素を追加する」みたいな場面では、
DocumentFragment を使うかどうかで体感が変わることもあります。


例題:1000 個の li 要素を一気に追加する

HTML

<ul id="list"></ul>

DocumentFragment を使わない場合

const ul = document.querySelector("#list");

for (let i = 1; i <= 1000; i++) {
  const li = document.createElement("li");
  li.textContent = `アイテム ${i}`;
  ul.appendChild(li); // 1000 回 DOM に追加
}
JavaScript

appendChild のたびに、
ブラウザは「DOM が変わったな」と認識して、
再レイアウト・再描画の候補になります。

DocumentFragment を使う場合

const ul = document.querySelector("#list");
const frag = document.createDocumentFragment();

for (let i = 1; i <= 1000; i++) {
  const li = document.createElement("li");
  li.textContent = `アイテム ${i}`;
  frag.appendChild(li); // ここでは画面はまだ変わらない
}

// 最後に 1 回だけ DOM に追加
ul.appendChild(frag);
JavaScript

この場合、
実際に画面の DOM が変わるのは ul.appendChild(frag) の 1 回だけです。

「大量の要素を追加するときは、fragment にためてから一括で挿す」
というパターンを覚えておくと、
「なんか重いな」を避けやすくなります。


重要ポイント:DocumentFragment 自体は「親を持たない特別なノード」

fragment は「親を持たない一時的なルート」

DocumentFragment は、Node の一種ですが、
document のような「ルートノードのミニ版」として振る舞います。

frag.appendChild(...)
frag.firstChild
frag.childNodes

など、普通の要素と同じように子を持てますが、
frag.parentNode は常に null です。

つまり、
「どこにもぶら下がっていない、独立した小さな DOM ツリー」
として存在しているイメージです。

appendChild すると「中身だけ」が移動する

container.appendChild(frag);
JavaScript

としたとき、
frag 自体が挿入されるのではなく、
frag の子ノードたちが container に移動します。

その結果、frag は空になります。

console.log(frag.childNodes.length); // 0
JavaScript

この挙動は最初ちょっと不思議に感じるかもしれませんが、
「作業台から部品を全部持っていったら、作業台は空になる」
と考えるとしっくりきます。


例題:テンプレートから複製して fragment にためる

HTML(テンプレートを使うパターン)

<template id="item-template">
  <li class="item">
    <span class="name"></span>
    <span class="price"></span>
  </li>
</template>

<ul id="list"></ul>

JavaScript

const template = document.querySelector("#item-template");
const ul = document.querySelector("#list");
const frag = document.createDocumentFragment();

const data = [
  { name: "りんご", price: 200 },
  { name: "バナナ", price: 150 },
  { name: "みかん", price: 300 },
];

data.forEach((item) => {
  const clone = template.content.cloneNode(true);
  clone.querySelector(".name").textContent = item.name;
  clone.querySelector(".price").textContent = item.price + "円";
  frag.appendChild(clone);
});

ul.appendChild(frag);
JavaScript

ここでの流れは、

template から DOM を複製
複製した DOM を fragment にためる
最後に fragment を ul に一括で挿す

というものです。

テンプレート+DocumentFragment の組み合わせは、
「同じ構造の要素をたくさん作る」場面で非常によく使われます。


重要ポイント:小さなアプリでも「設計の意識」が変わる

「画面に出す前に組み立てる」という発想

DocumentFragment を知ると、
「とりあえず DOM に追加してからいじる」のではなく、
「画面に出す前に、裏で組み立ててから出す」
という発想が持てるようになります。

これは、UI 設計の質を上げるうえでかなり大事です。

裏で組み立てる
→ まとめて挿す
→ 必要なら差し替える

という流れを意識すると、
「チラつきが少ない」「無駄な再描画が少ない」
気持ちのいい UI になりやすいです。

小さな単位で使ってもいい

「1000 個の要素」みたいな極端な例だけでなく、
例えば「カードを 10 枚追加する」程度でも、
DocumentFragment を使うとコードの意図がはっきりします。

「これは一括追加なんだな」と読み手に伝わるので、
パフォーマンスだけでなく、可読性の面でもメリットがあります。


初心者として documentFragment で本当に掴んでほしいこと

DocumentFragment は「画面にまだ挿していない一時的な DOM コンテナ」
document.createDocumentFragment() で作り、そこに要素をどんどん append できる
最後に親要素に appendChild(fragment) すると、中身だけが一括で移動する
大量の要素を追加するときに、再描画を減らしてパフォーマンスを良くできる
「画面に出す前に裏で組み立てる」という設計の感覚が身につくと、一気にレベルが上がる

まずは、

<ul> に 100 個の <li>
「fragment あり」と「fragment なし」で追加してみて、
コードの見通しや動きの違いを自分の目で感じてみてください。

DocumentFragment は、
「DOM を雑にいじる」のではなく、「まとめて丁寧に扱う」ための道具
として、あなたの UI 実装を一段上のステージに連れていってくれます。

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