以下では、DOMの「ノードの複製(cloneNode)」を、仕組み・注意点・実用パターンまで体系的に解説します。
概要
Node.prototype.cloneNode(deep = false) は、あるノードをコピーして新しいノードを生成します。コピーはツリー外で作られるため、実際に画面へ反映するには appendChild や replaceWith などで既存DOMに挿入します。
-
浅い複製(shallow):
node.cloneNode()/cloneNode(false)
ノード自身と属性だけを複製。子ノードは含まれません。 -
深い複製(deep):
node.cloneNode(true)
子孫ノードを含む完全なサブツリーを複製。
複製時に「コピーされるもの / されないもの」
-
コピーされる
-
属性(
id,class,data-*,styleなど) -
子孫ノード(
deep=trueの場合) -
インラインイベント属性(例:
onclick="...")※属性なのでコピー対象
-
-
コピーされない
-
イベントリスナ(
addEventListenerで登録したものは複製されません) -
JS で動的に付与したプロパティ(例:
element.someCustomProp = ...) -
計算済みスタイル(Computed Style)。
style属性は複製されるが、CSSにより結果的に適用された見た目は「再計算」されます。 -
一部の内部状態(後述のフォーム/メディア/キャンバス参照)
-
実用上は「イベントは引き継がれない」と覚え、再バインドまたはイベント委譲を使うのが定石です。
フォーム要素の挙動(重要)
フォーム要素は 属性値 と 現在値(プロパティ) が分かれるため注意します。
-
input[type="text"],textareaの 現在の入力値 は、実装差の歴史があるため、自分で同期するのが安全です。 -
input[type="checkbox"|"radio"]の チェック状態 も同様に、属性(checked) と プロパティ(checked) を意識して同期してください。 -
selectの 選択状態(selected)も明示同期を推奨。 -
input[type="file"]はセキュリティ上、ファイル選択状態は複製されません(常に空)。
安全な同期パターン例:
メディア要素・キャンバス・スクリプトの挙動
-
<video>/<audio>の再生位置や再生状態は引き継がれません(属性初期状態に戻る)。 -
<canvas>は描画内容(ビットマップ)は複製されません。必要ならdrawImageで転写します。 -
<script>をクローンして挿入しても実行されません。必要なら改めてdocument.createElement('script')で生成し直し、srcかtextContentを設定します。
id の重複とアクセシビリティ属性
id の重複とアクセシビリティ属性deep=true で複製すると、子孫にある id が丸ごと重複 します。label[for], aria-labelledby などの 参照関係 が壊れる原因になるため、複製後に id を付け替えるのが安全です。
イベントの再バインドとイベント委譲
-
再バインド: クローン後に必要なイベントを付け直す
-
イベント委譲: 親でまとめてイベントを受ける(クローンでも不要な再バインドが減る)
テンプレートとの併用(高速・安全)
頻繁に複製する UI は <template> を使うと高速・安全です。<template> の中身は非表示かつ非アクティブで、content.cloneNode(true) で必要なときに深い複製を得られます。
文書・フレーム間の複製
-
近年のブラウザでは、別ドキュメントから持ってきたノードを appendChild するときに自動的に**養子化(adopt)**されるため、importNode を明示的に呼ばなくても動くことが多いです。互換性を厳密に見るなら document.importNode(node, true) を使ってから挿入します。
よくある落とし穴チェックリスト
-
deep を付け忘れて子要素が消える
-
複製後の id 重複 を放置
-
イベントが引き継がれない(再バインド or 委譲の採用)
-
フォーム状態がズレる(値/チェック/選択を明示同期)
-
<canvas> の 描画内容が消える(ビットマップは別途コピー)
-
<script> が動かない(新規生成で挿入)
-
大きなサブツリーを頻繁に複製して パフォーマンス低下(<template> + DocumentFragment を活用)
-
structuredClone は DOM を複製しない(オブジェクト用API。DOMには cloneNode を使う)
まとめ
-
cloneNode(false) は「骨格(要素本体+属性)」、cloneNode(true) は「サブツリー丸ごと」を複製。
-
イベントは引き継がれないため、再バインドまたはイベント委譲を活用。
-
フォーム・メディア・キャンバスなどは状態がそのままにはならないことがあるため、明示的に同期/転写する。
-
繰り返し使うUIは <template> + content.cloneNode(true) が最適解。
ChatGPT5 生成日:2025/09/11