【jQuery】clone()メソッドで要素をコピーする完全ガイド|イベントコピー・動的フォーム追加まで

【jQuery】cloneメソッドで要素をコピーする方法 jQuery

jQueryの clone() メソッドを使うと、HTML要素をJavaScriptで複製できます。動的にフォームの入力行を追加したり、カードUIをコピーして展開するUIを手軽に実装できます。本記事では基本的なコピーからイベントの引き継ぎ・動的フォーム追加・deep cloneまで解説します。

この記事でわかること

  • clone()の基本的な使い方
  • イベントハンドラーをコピーする方法(第1引数 true)
  • 動的なフォーム行追加・削除の実装
  • cloneとappend/prependの組み合わせパターン
  • clone()使用時のよくある注意点
スポンサーリンク

1. clone()の基本構文

.clone() は選択した要素のディープコピーを作成して返します。コピーはDOM上に追加されるまで表示されません。

// 基本: 要素をコピーして別の場所に追加
var $copy = $('#original').clone();
$('#container').append($copy);

// 1行で書く
$('#original').clone().appendTo('#container');

// prependTo: コンテナの先頭に追加
$('#original').clone().prependTo('#container');

// insertAfter: 指定要素の直後に追加
$('#original').clone().insertAfter('#target');
clone()はDOMから元の要素を移動しない
clone() は要素を複製するだけで、元の要素はそのまま残ります。元の要素を移動したい場合は appendTo() のみを使ってください(clone不要)。

2. イベントハンドラーをコピーする(第1引数 true)

デフォルトでは clone() はHTML構造のみコピーし、jQueryで設定したイベントは引き継ぎません。イベントも含めてコピーするには clone(true) を使います。

$(function () {
  // オリジナルにイベントを設定
  $('#original button').on('click', function () {
    alert('クリックされました');
  });

  // clone() のみ: イベントはコピーされない
  var $copy1 = $('#original').clone();

  // clone(true): イベントもコピーされる
  var $copy2 = $('#original').clone(true);

  // clone(true, true): 子要素のイベントもコピーされる
  var $copy3 = $('#original').clone(true, true);

  $('#container').append($copy1).append($copy2).append($copy3);
});
引数 要素のコピー 直属イベント 子要素のイベント
clone() あり なし なし
clone(true) あり あり なし
clone(true, true) あり あり あり

3. 動的フォーム行の追加・削除

「入力行を追加」ボタンで行を複製し、「削除」ボタンで行を消す実用的なUIです。

<div id="form-wrapper">
  <div class="form-row">
    <input type="text" name="item[]" placeholder="商品名">
    <input type="number" name="qty[]" placeholder="数量">
    <button type="button" class="btn-remove">削除</button>
  </div>
</div>
<button type="button" id="btn-add">+行を追加</button>
$(function () {
  // 行を追加
  $('#btn-add').on('click', function () {
    var $original = $('.form-row').first();
    var $newRow   = $original.clone();
    $newRow.find('input').val('');  // 入力値をクリア
    $newRow.appendTo('#form-wrapper');
  });

  // 行を削除(動的に追加された要素にも対応するため on() を使う)
  $(document).on('click', '.btn-remove', function () {
    if ($('.form-row').length <= 1) return;  // 最低1行は残す
    $(this).closest('.form-row').remove();
  });
});
動的追加後のイベントは on() で委任する
clone()で追加した要素は後から追加されるため、直接 .on("click", ...) を設定しても効きません。$(document).on("click", ".btn-remove", ...) のように親要素に対して委任(event delegation)してください。

4. カードUIをコピーして表示数を増やす

テンプレートカードをcloneして、コンテンツを動的に入れ替えて複数表示する実装です。

<!-- テンプレート(非表示にしておく) -->
<div id="card-template" style="display:none">
  <div class="card">
    <h3 class="card-title"></h3>
    <p class="card-desc"></p>
  </div>
</div>
<div id="card-container"></div>
$(function () {
  // データ(実際はAjaxで取得することが多い)
  var items = [
    { title: "商品A", desc: "説明文A" },
    { title: "商品B", desc: "説明文B" },
    { title: "商品C", desc: "説明文C" }
  ];

  items.forEach(function (item) {
    var $card = $('#card-template .card').clone();
    $card.find('.card-title').text(item.title);
    $card.find('.card-desc').text(item.desc);
    $('#card-container').append($card);
  });
});

5. clone()とid重複問題

id 属性を持つ要素をcloneすると、ページ内に同一 id が複数存在することになります。これはHTML仕様違反でJSの動作が不定になります。クローン後にidを変更するかid自体をなくしましょう。

var $copy = $('#original').clone();

// id を別名に変更する
$copy.attr('id', 'copy-1');

// id を削除する
$copy.removeAttr('id');

// 子要素の id も再帰的に処理する
$copy.find('[id]').each(function () {
  $(this).attr('id', $(this).attr('id') + '-copy');
});

6. バニラJSでの代替(cloneNode)

jQuery不要の場合は cloneNode() が使えます。

var original = document.getElementById('original');

// shallow copy(子要素なし)
var shallowCopy = original.cloneNode(false);

// deep copy(子要素あり)
var deepCopy = original.cloneNode(true);

document.getElementById('container').appendChild(deepCopy);

まとめ

jQueryの clone() はHTML要素を丸ごとコピーできる便利なメソッドです。動的フォーム追加・カードUI・テンプレート複製など幅広いシーンで活躍します。イベントも引き継ぐ場合は clone(true)、id重複問題には要注意です。

関連記事: jQueryで指定した要素の前後に追加する方法 / jQueryで要素を削除する方法

よくある質問(FAQ)

Qclone()でコピーしたがイベントが動かない
Aclone(true) を使うとjQueryのイベントハンドラーも引き継ぎます。子要素のイベントも含めるには clone(true, true) にしてください。また、動的追加後の要素には $(document).on() でイベント委任する方法も効果的です。
Qcloneした要素のidが重複してしまう
Aクローン後に .attr("id", "新しいid") でidを変更するか、.removeAttr("id") でid属性を削除してください。子要素のidも .find("[id]") で一括処理できます。
Qcloneした後に入力値をクリアしたい
A$copy.find("input, textarea, select").val(""); でクローン内の全フォーム要素をリセットできます。チェックボックスは .prop("checked", false) で対応してください。
Qclone()とappendTo()の違いは何ですか?
AappendTo() は元の要素を移動します。clone().appendTo() は複製を移動し、元の要素は残ります。元の要素を残したい場合は必ず clone() を挟んでください。
QjQuery不要でcloneと同等の処理をするには?
AバニラJSの element.cloneNode(true) が同等です。第1引数に true を渡すと子要素を含むディープコピーになります。イベントリスナーはjQuery同様コピーされないため、クローン後に再設定が必要です。