cloneNode とは何か
cloneNode は、既存の DOM ノード(要素やテキスト)を“複製”するメソッドです。形は node.cloneNode(deep)。ここが重要です:deep が false(省略時は false)なら“その要素だけ”をコピー、true なら“子孫を含めて丸ごと”コピーします。複製したノードはまだ画面に表示されないので、必要な変更を加えてから親へ追加します。
基本の使い方(浅い複製と深い複製の違い)
浅い複製(子は含めない)
<div id="card" class="card">
<h3>タイトル</h3>
<p>本文</p>
</div>
<script>
const card = document.getElementById("card");
const copy = card.cloneNode(); // = cloneNode(false)
// copy には class や属性は複製されるが、子要素 (h3, p) はない
document.body.appendChild(copy);
</script>
HTMLここが重要です:浅い複製は“枠だけ”欲しいときに使います。内部構造が不要な場合は軽くて安全です。
深い複製(子孫も含める)
const card = document.getElementById("card");
const deepCopy = card.cloneNode(true); // 子孫まで全部コピー
document.body.appendChild(deepCopy);
JavaScriptここが重要です:UI 部品を“そのままもう1個”作るなら深い複製。イベントリスナーはコピーされないため、必要なら後で付け直します。
何がコピーされ、何がコピーされないか(重要ポイントを深掘り)
コピーされるもの
属性(id, class, data-* など)と、テキスト・子要素の“構造”はコピーされます。style 属性の中身も複製されます。
コピーされないもの
追加したイベントリスナー(addEventListener の登録)は複製されません。input の“現在値”などのプロパティ状態も、基本は初期状態へ戻ることがあります。ここが重要です:動的な状態(イベント・現在値・一時 URL の関連付け)は“あとから付け直す”のが定石です。
const btn = document.getElementById("btn");
btn.addEventListener("click", () => console.log("original"));
const copy = btn.cloneNode(true);
// copy には click リスナーがない → 必要なら付け直す
copy.addEventListener("click", () => console.log("copy"));
JavaScriptid の重複に注意(ユニーク性の維持)
同じ id を持つ要素を複製してそのまま挿入すると、文書内で id が重複してセレクタや参照が壊れます。ここが重要です:clone 後に id を必ず付け替えるか、id をもたないテンプレートを使い、必要箇所だけ一意な識別子を振ります。
const card = document.getElementById("card"); // id="card"
const copy = card.cloneNode(true);
copy.id = "card-copy"; // 一意に変更
document.body.appendChild(copy);
JavaScript複製後のカスタマイズ(テキスト・属性・画像・イベント)
文言や画像の差し替え
const tpl = document.getElementById("product"); // 子要素に .title, .price, img がある前提
const copy = tpl.cloneNode(true);
copy.querySelector(".title").textContent = "りんご";
copy.querySelector(".price").textContent = "¥120";
const img = copy.querySelector("img");
img.src = "/img/apple.png";
img.alt = "りんご";
document.getElementById("list").appendChild(copy);
JavaScriptここが重要です:clone → 中身を書き換え → append の型を身につけると、繰り返し UI を安全・高速に生成できます。
イベントの付け直し
const copyBtn = copy.querySelector(".buy");
copyBtn.addEventListener("click", () => {
copyBtn.disabled = true;
copyBtn.textContent = "購入済み";
});
JavaScriptここが重要です:リスナーは複製されないため“必要なイベントは clone 後に付ける”を習慣化します。
テンプレートと cloneNode(最強コンボ)
<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) {
const node = document.getElementById("tpl-card").content.cloneNode(true); // 深い複製
node.querySelector(".title").textContent = item.title;
node.querySelector(".desc").textContent = item.desc;
const btn = node.querySelector(".buy");
btn.addEventListener("click", () => btn.textContent = "購入済み");
document.getElementById("root").appendChild(node);
}
render({ title: "りんご", desc: "甘いです" });
</script>
HTMLここが重要です:template.content は“画面に描画されない雛形”。cloneNode(true) で安全に複製し、中身だけ差し替えると、XSS や構造崩れの心配が減ります。
パフォーマンスのコツ(大量生成・フラグメント)
多数の複製を挿入する場合は DocumentFragment にまとめてから一度で追加します。ここが重要です:1件ずつ挿すより“まとめて”のほうがレイアウト再計算が減り軽くなります。
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const copy = tpl.content.cloneNode(true);
copy.querySelector(".title").textContent = `項目 ${i}`;
frag.appendChild(copy);
}
document.getElementById("root").appendChild(frag);
JavaScript実務パターン(行追加、差し替え、ドラフト複製)
行の追加(同じ形を増やす)
const row = document.querySelector(".row"); // 雛形行
function addRow(text) {
const copy = row.cloneNode(true);
copy.querySelector(".text").textContent = text;
document.getElementById("list").appendChild(copy);
}
addRow("新しい行");
JavaScript置換(既存行を丸ごと作り直し)
function replaceRow(old) {
const fresh = old.cloneNode(true);
fresh.querySelector(".status").textContent = "更新済み";
old.replaceWith(fresh);
}
JavaScriptここが重要です:既存構造を保ちながら“中身だけ差し替え”。レイアウトやスタイルの安定性が高いです。
編集用ドラフトを複製して保管
const form = document.getElementById("edit-form");
const draft = form.cloneNode(true); // 深い複製でドラフト作成
// 編集をキャンセルしたら draft で元に戻す
form.replaceWith(draft);
JavaScriptここが重要です:clone を“巻き戻し用のスナップショット”として使うと、Undo が簡単に書けます。
よくある落とし穴と回避策
イベントが複製されないため、必ず付け直す。id は一意に変更する。input・video などの“現在状態”は clone で期待通りにならないことがあるので、clone 後に value/checked/currentTime などを明示的に設定する。Object URL を使う画像は差し替え時に URL.revokeObjectURL で解放する。ここが重要です:clone は“構造と属性のコピー”、動的な“状態と振る舞い”は後から整える。
まとめ
cloneNode は「既存ノードの複製」を行う基本メソッドです。浅い複製(構造のみ)と深い複製(子孫含む)を使い分け、イベントは付け直す、id は一意にする、必要なプロパティ(value/checked など)は明示的に再設定。大量生成は DocumentFragment、複雑な UI は template+cloneNode の組み合わせが定石。これらを守れば、初心者でも安全で効率的に“同じ形の UI”を増やし、差し替えやドラフト管理をスマートに実装できます。
