jQuery / Method / .clone() - 選択した要素を複製するメソッド
jQueryの .clone() は、選択要素と子孫・テキストを複製した新しいjQueryオブジェクトを作ります。複製だけでは画面に入らないので.appendTo()などで挿入します。jQueryイベントとデータは既定では含まず、引数で別に指定します。
構造・移動・イベントのオプション
.clone() の公式文書の深い構造複製は、子要素までコピーする意味です。イベントや.data()内のすべての入れ子オブジェクトが独立する意味ではありません。第2引数deepWithDataAndEventsは子孫のjQueryイベント・データを制御し、DOMの子を複製するかどうかの指定ではありません。
| 式 | 要素と子孫構造 | ルートのイベント・データ | 子孫のイベント・データ |
|---|---|---|---|
| .clone() | 複製 | 複製しない | 複製しない |
| .clone(true, false) | 複製 | 複製 | 複製しない |
| .clone(true, true) | 複製 | 複製 | 複製 |
| .clone(true) | 複製 | 複製 | 第2引数が第1に従い複製 |
既存要素を1か所へ.appendTo()で入れると元の場所から移動します。原本を残すなら先に複製してから挿入します。別々のDOM(Document Object Model、文書オブジェクトモデル)要素なので、複製の見出しを変えても原本は変わりません。
カードのデータとクリックを比べる完全な例
全コードをUTF-8の clone-demo.html に保存し、ブラウザーで開きます。公式CDN(Content Delivery Network、コンテンツ配信ネットワーク)のjQuery 4.0.0を読む接続が必要ですがインストールは不要です。3つの複製モード、クリック、データ共有、リセットを3.7.1と4.0.0で実行確認しました。
原本ルートにはcountとkindをjQueryデータとして保存し、内部のIncrementボタンへ直接イベントを登録します。複製のcountと表示数は比較用にコードで0へ戻します。複製すれば自動的にカウンターが0になるわけではありません。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Clone structure, data and events</title>
<style>
body { font: 16px/1.6 sans-serif; margin: 24px; }
.card { padding: 14px; margin: 12px 0; border: 1px solid #8aa; }
.card p { margin: 4px 0; }
button { margin: 4px; padding: 8px; }
</style>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
</head>
<body>
<h1>Clone structure, data and events</h1>
<div class="card" id="source">
<p class="label">Original</p>
<p>Count: <span class="count">0</span></p>
<p>Data: <span class="data">stored</span></p>
<button type="button" class="increment">Increment</button>
</div>
<button type="button" id="plain">Clone structure</button>
<button type="button" id="parent">Clone parent data</button>
<button type="button" id="full">Clone events</button>
<button type="button" id="reset">Reset</button>
<div id="copies"></div>
<p id="result" aria-live="polite"></p>
<script>
$(function () {
const $source = $("#source").data({ count: 0, kind: "stored" });
let serial = 1;
function report() {
$("#result").text(`source=${$source.data("count")} | copies=${$("#copies > .card").length}`);
}
$source.find(".increment").on("click", function () {
const $card = $(this).closest(".card");
const count = $card.data("count") + 1;
$card.data("count", count).find(".count").text(count);
report();
});
function copy(withData, deep) {
const $copy = $source.clone(withData, deep);
$copy.attr("id", "copy-" + serial);
$copy.find(".label").text("Copy " + serial++);
$copy.data("count", 0).find(".count").text(0);
$copy.find(".data").text($copy.data("kind") || "none");
$copy.appendTo("#copies");
report();
}
$("#plain").on("click", () => copy(false, false));
$("#parent").on("click", () => copy(true, false));
$("#full").on("click", () => copy(true, true));
$("#reset").on("click", function () {
$("#copies").empty();
serial = 1;
$source.data("count", 0).find(".count").text(0);
report();
});
report();
});
</script>
</body>
</html>
最初は原本だけで、結果は次のとおりです。
source=0 | copies=0
- 原本の Increment を1回押し、Countを1にします。
- Clone structure は構造だけをコピーし、kindとイベントは含みません。Copy 1のDataはnoneで、押しても0のままです。
- Clone parent data はルートのkindをコピーしてstoredと表示しますが、子孫ボタンのイベントはなく増えません。
- Clone events は子孫イベントも含みます。Copy 3を押すとそのカードだけ1となり、原本も1のままです。
- Reset は全複製を除去し、原本カウンターと複製番号を初期化します。原本イベントを再登録しないため、繰り返しても1クリックで1回だけ増えます。
挿入前にルートIDをcopy-1など一意に変え、内部はクラスで識別します。子孫IDやlabelのfor、aria-controlsがあるなら、IDと参照先をまとめて新しくします。
入れ子のオブジェクトと配列は明示的にコピー
.clone(true)でコピーした.data()内のオブジェクトや配列は共有され得ます。開発者ツールのConsoleで全体を実行し、画面に入れない一時要素で違いを比べます。
const $original = $("<div>").data("options", { tags: ["a"] });
const $shared = $original.clone(true);
$shared.data("options").tags.push("b");
console.log($original.data("options").tags.join(", "));
const $independent = $original.clone(true).data("options", {
tags: [...$original.data("options").tags]
});
$independent.data("options").tags.push("c");
console.log($original.data("options").tags.join(", "));
console.log($independent.data("options").tags.join(", "));
a, b
a, b
a, b, c
最初の複製でbを追加すると、同じoptionsを参照する原本もa, bです。独立版は新しいoptionsとtags配列を設定するため、cを追加しても原本はa, bのままです。既知の文字列配列の構造をコピーした例で、任意の深いオブジェクトをすべて独立させる汎用処理ではありません。
フォーム状態・イベント設計・問題の確認
すべてのフォーム部品の現在状態が同じようにコピーされるとは限りません。公式文書はinputの動的状態とtextarea・selectを区別しています。必要な値を確認し、選択値やメモは複製後.val()で明示的に設定する方法を検討します。
新しいカードを動かすため必ず全イベントを複製する必要はありません。維持される親の.on() によるイベント委譲なら追加した子孫も扱えます。直接イベントのコピーと委譲を併用すると同じ処理が2回動く場合があるため、必要な方式を選んで結果を確認します。
見えなければ挿入処理と挿入先の存在、ボタンが動かなければ登録先がルートか子孫かと両引数を確認します。空の選択は空の複製で、重複IDは選択やラベルを誤接続させます。Networkの読み込みとConsoleのエラーも調べます。




