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()で追加した要素は後から追加されるため、直接
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()でコピーしたがイベントが動かない
A
clone(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()の違いは何ですか?
A
appendTo() は元の要素を移動します。clone().appendTo() は複製を移動し、元の要素は残ります。元の要素を残したい場合は必ず clone() を挟んでください。QjQuery不要でcloneと同等の処理をするには?
AバニラJSの
element.cloneNode(true) が同等です。第1引数に true を渡すと子要素を含むディープコピーになります。イベントリスナーはjQuery同様コピーされないため、クローン後に再設定が必要です。

