9.

jQueryで要素をコピーする方法|clone(true)でイベント込み複製

編集
この記事の要点
  • jQuery で要素を複製するには $(selector).clone() を使う
  • clone()イベントハンドラやデータをコピーしないのが既定。コピーするには clone(true)
  • 複製後は appendTo() / prependTo() / before() / after() でどこに挿入するかを指定する
  • id 属性もそのまま複製されるため、ID 重複に注意 — 複製後に書き換えるかクラスベースに設計する
  • 純粋 JS なら Node.cloneNode(true)。SPA / モダン開発では vanilla JS で十分なケースも多い

jQuery clone() の基本

clone() は jQuery オブジェクトをディープコピーするメソッドです。元の要素を残したまま同じ HTML 構造を複製し、appendTo などで好きな場所に挿入できます。動的なフォーム追加、リスト項目の追加 UI などに頻出する基本機能です。

HTML

<div id="item_list">
  <input id="item" type="text">
</div>

<input type="button" onclick="copyItem()" value="コピーボタン">

上記の <input id="item"> をコピーする例です。

jQuery 実装

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
function copyItem() {
  $("#item").clone().appendTo("#item_list");
}
</script>

clone() でコピー、appendTo()#item_list の末尾に追加しています。これだけで「ボタンを押すたびに input が増える」ような動的フォームを実現できます。

clone() と clone(true) の違い

呼び方イベントハンドラdata()用途
clone()コピーしないコピーしないHTML 構造のみ複製
clone(true)コピーするコピーするイベント込みで複製
clone(true, true)コピー + 子孫もコピー + 子孫も完全な深いコピー
// 例: クリックイベント付きボタンを複製
$("#origBtn").on("click", function() {
  alert("クリックされた!");
});

$("#origBtn").clone().appendTo("body");
// コピー先のボタンを押しても何も起きない

$("#origBtn").clone(true).appendTo("body");
// コピー先のボタンも同じアラートが出る

挿入位置の指定

メソッド挿入位置
appendTo(parent)親の末尾(子要素として)
prependTo(parent)親の先頭
insertAfter(target)対象の直後(同階層)
insertBefore(target)対象の直前
$("#item").clone().insertAfter("#item");          // 同じ階層、直後
$("#card").clone().prependTo("#list");            // リスト先頭に
$("#row").clone().insertBefore("#footerRow");     // フッター行の前に

ID 重複の罠

HTML の id 属性はドキュメント内で一意であるべきですが、clone() は属性をそのまま複製するため同じ id を持つ要素が複数できてしまいます。

// NG: 2 つの #item ができてしまう
$("#item").clone().appendTo("#item_list");

// OK: id を書き換える
let count = $("#item_list input").length;
$("#item")
  .clone()
  .attr("id", "item_" + count)         // id を一意化
  .removeAttr("name")                  // 必要に応じて
  .val("")                             // 値クリア
  .appendTo("#item_list");

// よりベストプラクティス: ID ではなくクラスで設計
$(".item").first().clone().appendTo("#item_list");

動的フォーム追加の完全例

<div id="form-rows">
  <div class="row">
    <input type="text" name="items[]" placeholder="商品名">
    <input type="number" name="qty[]" placeholder="数量">
    <button type="button" class="remove">削除</button>
  </div>
</div>
<button type="button" id="addRow">行を追加</button>
$(function() {
  // 行追加
  $("#addRow").on("click", function() {
    const $row = $("#form-rows .row").first().clone();
    $row.find("input").val("");      // 値をクリア
    $row.appendTo("#form-rows");
  });

  // 行削除(イベント委譲)
  $("#form-rows").on("click", ".remove", function() {
    if ($("#form-rows .row").length > 1) {
      $(this).closest(".row").remove();
    }
  });
});

イベント委譲(on("click", ".remove", ...))を使えば、後から追加された行の削除ボタンにも自動でイベントが効きます。これと clone() を組み合わせるのが動的フォームの王道パターン。

外す系メソッドとの関係

メソッド挙動
clone()元を残してコピー
detach()DOM から外すが内部のデータ / イベントは保持
remove()DOM から削除、データもクリア
empty()子要素のみ削除

純粋な JavaScript(vanilla)での書き方

jQuery を使わない場合、Node.cloneNode(true) で同等の処理ができます。モダンブラウザではこれで十分なケースも多い。

function copyItem() {
  const orig = document.getElementById("item");
  const copy = orig.cloneNode(true);   // true で子孫もコピー
  copy.removeAttribute("id");          // ID 重複回避
  copy.value = "";
  document.getElementById("item_list").appendChild(copy);
}
項目jQuery clonecloneNode
子孫も複製常に深い引数 true で深い
イベントもコピーclone(true) で可cloneNode は不可(手動で設定)
jQuery 依存ありなし(標準 DOM API)

パフォーマンスの注意

  • 巨大な DOM を頻繁に clone するとメモリと描画コストが大きい
  • 追加が大量にあるならDocumentFragment を使ってまとめて挿入(vanilla JS の場合)
  • 頻繁な DOM 追加削除は仮想 DOM フレームワーク(React / Vue)の方が効率的

FAQ

Q: clone() でイベントが効かない
A: 既定の clone() はイベントをコピーしません。clone(true) を使うか、イベント委譲($(parent).on("click", ".child", ...))で解決します。後者の方がメモリ効率が良いです。

Q: フォームの value がコピーされない
A: ブラウザによっては input の値属性と value プロパティが別扱い。コピー後に .val("") でクリアしたり、.val(orig.val()) で改めて設定するのが安全。

Q: jQuery を使わずに同じことをしたい
A: element.cloneNode(true) + parent.appendChild() で同等です。イベントは addEventListener で都度設定。

関連

  • jQuery — DOM 操作を簡潔にするライブラリ
  • appendTo / prependTo — 要素の追加
  • on — イベントハンドラの設定(委譲も対応)
  • cloneNode — 純粋 JS の DOM 複製 API
  • DocumentFragment — 一括挿入の高速化
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 導入方法
  2. 文法
  3. HTML/CSS 操作・制御
  4. 要素の取得
  5. 値の取得
  6. jQuery で要素を追加(append / prepend / before / after / wrap)
  7. 値と要素の削除
  8. 子要素の削除
  9. 要素のコピー
  10. Ajax
  11. 項目をタッチ/クリックしてスライドさせる方法
  12. テキスト/セレクトボックス/ラジオボタン変更時のイベント
  13. パスワードを一時的に表示させる方法
  14. $(document).ready(function() { ...
  15. セレクトボックスにオプションを追加する方法

最近更新/作成されたページ