TECHBLOGスキルブログ

jQueryオブジェクトを.append()する時は気をつけよう

2019.03.01

こんにちは。
ユニトラストの宮本です。

昨今、Webアプリケーション開発においてJavascript抜きでは語れない時代になりました。
最近はReactVue.jsなどモダンなJavascriptフレームワークが流行っていますが、jQueryもまだまだ現役です。

今回はjQueryの.append()を使用するときに気をつけるポイントを書きたいと思います。

まず、jQueryの.append()のおさらい

簡単に説明すると、jQueryの.append()は各要素内の一番後ろに指定したHTMLやエレメントを挿入します。

ex)
次のようなHTMLがあったとして

<div>
    <div class="hello">
        こんにちは
    </div>
</div>

次のようなjsが実行されると

// class="hello"に該当するセレクタの一番後ろに'<p>テスト</p>'を追加
$('.hello').append('<p>テスト</p>');

次のようなHTMLになります

<div>
    <div class="hello">
        こんにちは
        <p>テスト</p>
    </div>
</div>

jQueryオブジェクトを.append()する時は気をつけよう

複数の要素に対して同一のjQueryオブジェクトを.append()する時

ex)
ボタンをクリックしたら.test_1と.test_2にhello!を追加する処理

次のようなHTML・jsがあるとして

<button>add word</button>

<div>
    <p class="test_1">
        test1
    </p>
    <p class="test_2">
        test2
    </p>
</div>
var button = $("button")

// クリックしたら.test_1と.test_2に<span class="hi">hello!</span>を追加
button.on("click", function(){
    // <span class="hi">hello!</span>のDOM要素(jQueryオブジェクト)を生成・変数にする
    var $ele = $('<span />', {class: 'hi'}).append('hello!');
    // $eleを.test_1と.test_2に追加
    $('.test_1').append($ele);
    $('.test_2').append($ele);
});

見本その1

ボタンをクリックした時、

想定では

<button>add word</button>

<div>
    <p class="test_1">
        test1
        <span class="hi">hello!</span>
    </p>
    <p class="test_2">
        test2
        <span class="hi">hello!</span>
    </p>
</div>

見本その2

になる!…と思われがちですが、実際には

<button>add word</button>

<div>
    <p class="test_1">
        test1
    </p>
    <p class="test_2">
        test2
        <span class="hi">hello!</span>
    </p>
</div>

見本その3

の様になってしまいます。

一体どういうことなのでしょうか?

jQueryオブジェクトの.append()は追加 or 移動

困った時はまず、公式マニュアルを読みましょう!

jQuery公式マニュアル .append()

原因が書いてありました。

If an element selected this way is inserted into a single location elsewhere in the DOM, it will be moved into the target (not cloned)
Important: If there is more than one target element, however, cloned copies of the inserted element will be created for each target except for the last one.

google翻訳 ↓

この方法で選択された要素がDOMの他の場所の単一の場所に挿入された場合、それはターゲットに移動されます(クローンされません)
重要:ただし、ターゲット要素が複数ある場合は、最後の要素を除く各ターゲットに対して、挿入された要素のクローンコピーが作成されます。

つまり、処理の流れを説明すると

ボタンをクリック

DOM要素を生成・変数にする

var $ele = $('<span />', {class: 'hi'}).append('hello!');


作成した変数($ele)をclass=”test_1″に該当するセレクタの一番後ろに追加する

$('.test_1').append($ele);

この段階ではこうなっている

<button>add word</button>

<div>
    <p class="test_1">
        test1
        <span class="hi">hello!</span>
    </p>
    <p class="test_2">
        test2
    </p>
</div>


作成した変数($ele)をclass=”test_2″に該当するセレクタの一番後ろに追加するのではなく、作成した変数($ele)をclass=”test_2″に該当するセレクタの一番後ろに移動させる

$('.test_2').append($ele);

この段階でこうなってしまう!

<button>add word</button>

<div>
    <p class="test_1">
        test1
    </p>
    <p class="test_2">
        test2
        <span class="hi">hello!</span>
    </p>
</div>


結果、最後にappendした要素にのみ適用されてしまったのです。

では、どうする?

【解決法】.append()する時に、変数を複製(.clone())する!

    $('.test_1').append($ele);
    $('.test_2').append($ele);

    // $eleを複製する($eleと$ele_clone_1は内容は同じだけど、別の変数になる)
    var $ele_clone_1 = $ele.clone();
    $('.test_1').append($ele_clone_1);
    var $ele_clone_2 = $ele.clone();
    $('.test_2').append($ele_clone_2);

もしくは

    // こちらでもOK
    $('.test_1').append($ele.clone());
    $('.test_2').append($ele.clone());

複製された変数を.append()することで、要素を追加する。
とてもわかりやすいですね。

【非推奨】この方法でも解決できることは出来る

変数に代入する値をjQueryオブジェクトではなく文字列にしてしまえばいい!

var $ele = $('<span />', {class: 'hi'}).append('hello!');

var $ele = $('<span />', {class: 'hi'}).append('hello!')[0].outerHTML;

.append()の引数がjQueryオブジェクトでなければ単純に文字列が追加される。
こちらでもできますが、読みづらいのでおすすめしません。

ちなみに

次のような場合はどうなるでしょうか?

<button>add word</button>

<div>
    <p class="test">
        test1
    </p>
    <p class="test">
        test2
    </p>
</div>
var button = $("button")

// クリックしたら全ての.testに<span class="hi">hello!</span>を追加
button.on("click", function(){
    // <span class="hi">hello!</span>のDOM要素(jQueryオブジェクト)を生成・変数にする
    var $ele = $('<span />', {class: 'hi'}).append('hello!');
    // $eleを全ての.testに追加
    $('.test').append($ele);
});

上記の場合には、要素が全てに追加(実際は要素が複製された上で追加)されます。

<button>add word</button>

<div>
    <p class="test">
        test1
        <span class="hi">hello!</span> //要素が複製された上で追加
    </p>
    <p class="test">
        test2
        <span class="hi">hello!</span> //最後のターゲットだけ要素がそのまま追加
    </p>
</div>

この方法で選択された要素がDOMの他の場所の単一の場所に挿入された場合、それはターゲットに移動されます(クローンされません)
重要:ただし、ターゲット要素が複数ある場合は、最後の要素を除く各ターゲットに対して、挿入された要素のクローンコピーが作成されます。

ターゲット要素(.test)が2つあるので、最後のターゲット以外は複製された$eleが挿入され、
全てのターゲット要素(.test)に対して、$eleの内容が追加されます。

まとめ

様々なJavascriptフレームワークが登場し始め、いよいよお役御免と思われがちなjQueryですが、
2019年2月現在、世界上位50万サイトの90%近くがまだjQueryを使用しています。

まだまだ使う機会が多いjQuery、一度学びなおしてみてはいかがでしょうか?

jQuery公式サイト[https://jquery.com/]

              

OTHER CONTENTSその他のコンテンツ

UNITRUST会社を知る

  • 私たちについて

  • 企業情報

SERVICE事業内容

  • システム開発

  • 自社サービス

CONTACT
お問い合わせ

あなたの「想い」に挑戦します。

どうぞお気軽にお問い合わせください。

受付時間:平日9:00〜18:00 日・祝日・弊社指定休業日は除く

お問い合わせ