jQueryオブジェクトを.append()する時は気をつけよう
2019.03.01
こんにちは。
ユニトラストの宮本です。
昨今、Webアプリケーション開発においてJavascript抜きでは語れない時代になりました。
最近はReactやVue.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); });
ボタンをクリックした時、
想定では
<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>
になる!…と思われがちですが、実際には
<button>add word</button> <div> <p class="test_1"> test1 </p> <p class="test_2"> test2 <span class="hi">hello!</span> </p> </div>
の様になってしまいます。
一体どういうことなのでしょうか?
jQueryオブジェクトの.append()は追加 or 移動
困った時はまず、公式マニュアルを読みましょう!
原因が書いてありました。
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/]
CONTACT
お問い合わせ
あなたの「想い」に挑戦します。
どうぞお気軽にお問い合わせください。
受付時間:平日9:00〜18:00 日・祝日・弊社指定休業日は除く