概要
jQuery の .html
で公式にない仕様を確認した為、jQuery v3.1.1 を元に仕様を調査してみました。
jQuery.prototype
この節は本題とは無関係なので読み飛ばしても構いません。
いわゆる「jQuery オブジェクト」と呼ばれるものは new jQuery
のようにして生成されており、jQuery.prototype
上にあるメソッドを扱えます。
console.log(jQuery('p') instanceof jQuery); // true
console.log(new jQuery('p') instanceof jQuery); // true
console.log(jQuery('p').html === jQuery.prototype.html); // true
console.log(jQuery.fn === jQuery.prototype); // true
jQuery plugin を作る時に jQuery.fn
にメソッドを代入していますが、内部的には jQuery.prototype
に代入されています。
また、jQuery('p')
と new jQuery('p')
は等価です。
本記事では jQuery.prototype.empty
を jQuery#empty
と表記します。
jQueryの公式ドキュメント上では jQuery.prototype.html
を .html()
のように表記しています。
.html()
引数なしの .html()
は DOM API である element.innerHTML
の getter として評価されます。
<div id="sample">This is a sample.</div>
<script>
console.log(jQuery('#sample').html()); // "This is a sample."
</script>
他の多くのgetter系 jQuery API と同じく、.html()
は jQuery オブジェクト群の初めの要素ノードに対して処理されます。
<div class="sample">This is a pen.</div>
<div class="sample">This is a book.</div>
<div class="sample">This is a eraser.</div>
<script>
console.log(jQuery('.sample').html()); // "This is a pen.<"
</script>
.html( htmlString )
.html()
に String
型の引数が与えられた場合、DOM API である element.innerHTML
の setter として評価されます。
<div id="sample">This is a sample.</div>
<script>
console.log(jQuery('#sample').html('<strong>This is a jQuery</strong>')); // [div#sample] ← 評価値は jQuery('#sample') になります
.html(htmlString)
は対応する jQuery オブジェクト群の全てに適用されます。
<!-- 下記3つとも "<strong>This is a jQuery</strong>" に置換される -->
<div class="sample">This is a pen.</div>
<div class="sample">This is a book.</div>
<div class="sample">This is a eraser.</div>
<script>
console.log(jQuery('.sample').html('<strong>This is a jQuery</strong>')); // [div.sample, div.sample, div.sample]
</script>
.html( function )
関数を引数にした .html()
はコールバック関数に「インデックス」「element.innerHTML
」を渡して全てのjQueryオブジェクトに innerHTML
の setter 処理を行います。
<!-- 下記3つとも '<strong>" + htmlString + '"</strong>'' に置換される -->
<div class="sample">This is a pen.</div>
<div class="sample">This is a book.</div>
<div class="sample">This is a eraser.</div>
<script>
console.log(jQuery('.sample').html(function (index, htmlString) {
return '<strong>"' + htmlString + '"</strong>';
})); // [div.sample, div.sample, div.sample]
[隠し仕様] .html( DOMNode or jQueryObject) (v.3.1.1 現在)
公式リファレンスでは言及されていませんが、jQuery v3.1.1 ではDOMノードやjQueryオブジェクトを引数にとることもできるようです。
(注意: この仕様はリファレンスにない以上、公式に認められた仕様ではないので今後の更新で削除される可能性があります。原則として使わない事をお勧めします。)
jQueryオブジェクトが引数にとられた場合、当該要素の子要素を全て削除(jQuery#empty
の処理が実行されます)した後に当該jQueryオブジェクトを jQuery#append
します。
<div id="sample">This is a sample.</div>
<script>
jQuery('#sample').html(jQuery('<strong>replaced text.</strong>'));
</script>
引数がDOMノードであった場合、一度 jQuery オブジェクトに変換してから先と同様の処理を行います。
<div id="sample-1">This is a pen.</div>
<div id="sample-2">This is a book.</div>
<script>
/**
* 要素ノード
*/
var strong = document.createElement('strong');
strong.textContent = 'replaced text 1.';
jQuery('#sample-1').html(strong);
/**
* DocumentFragment
*/
var df = document.createDocumentFragment(),
p = document.createElement('p');
for (var i = 1; i < 4; ++i) {
p.textContent = 'This is a sample-2-' + i;
df.appendChild(p.cloneNode(true));
}
jQuery('#sample-2').html(df);
</script>
まとめ
公式ドキュメントでは .html()
が文字列を対象に取るメソッドと説明されている為、それに則るのが好ましいと思います。
DOMノードが必要なら次の2つの対策が考えられます。
jQuery(selector).empty().append(domNode)
- DOM API で完結したコードを書く (
Node#removeChild
->appendChild
)
<div id="parent-1">
<div id="child-1-1">child-1-1</div>
<div id="child-1-2">child-1-2</div>
<div id="child-1-3">child-1-3</div>
</div>
<div id="parent-2">
<div id="child-2-1">child-2-1</div>
<div id="child-2-2">child-2-2</div>
<div id="child-2-3">child-2-3</div>
</div>
<script>
'use strict';
/**
* createDocumentFragment
*/
function createDFNode (textList) {
var df = document.createDocumentFragment(),
p = document.createElement('p');
for (var i = 0, len = textList.length; i < len; ++i) {
p.textContent = textList[i];
df.appendChild(p.cloneNode(true));
}
return df;
}
/**
* jQuery#empty -> jQuery#append (jQuery API)
*/
jQuery('#parent-1').empty().append(createDFNode(['text1-1', 'text1-2', , 'text1-3']));
/**
* Node#removeChild -> appendChild
*/
var parent = document.getElementById('parent-2');
Array.from(parent.childNodes).forEach(function (node) {
node.parentNode.removeChild(node);
});
parent.appendChild(createDFNode(['text2-1', 'text2-2', , 'text2-3']));
</script>
参考リンク
「公式リファレンス」と「jquery-3.1.1.js のソースコード(.html
の該当行: 5978行目)」。