Edited at

innerHTML より insertAdjacentHTML を使う

More than 1 year has passed since last update.


はじめに

とある要素の中をいじりたいという時 innerHTML で操作することもあるかもしれません。

しかし、実はこれはあまりよろしくない。


innerHTML は既存の要素を破壊(?)する

innerHTML を書き換えるということはつまり、要素の中身をすべて新しいものに書き換えるということです。

既存の要素は、新たな要素として扱われてしまいます。


サンプル

例えば、以下のようなHTMLとJavaScriptコードがあったとします。


HTML

<div id="contentBlock">

<button id="clickButton">Click Here</button>
</div>


JavaScript

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

clickButton.addEventListener('click', function () {
alert('Alert!');
});

ボタンをクリックするとアラートが出るだけの簡単なやつです。

では、button要素の前に innerHTML を使用して文字列を追加してみます。


JavaScript

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

contentBlock.innerHTML = '<b>Test:</b>' + contentBlock.innerHTML;

するとどうでしょう、ボタンをクリックしても反応しなくなりました。

#contentBlock 内のbutton要素は innerHTML によってHTML文字列として取得され、innerHTML によって新たなHTMLとして #contentBlock に挿入されます。

なので、挿入前と挿入後のbutton要素は別物なのです。


insertAdjacentHTML は既存の要素を破壊しない

element.insertAdjacentHTML - Web API インターフェイス | MDN

insertAdjacentHTML は文字列をHTMLとしてパースしたものを指定した箇所に挿入するメソッドです。


構文

element.insertAdjacentHTML(position, text);


position で挿入する箇所を指定、text で挿入するHTML文字列となっています。

position には以下の4つが指定できます。


  • 'beforebegin'

  • 'afterbegin'

  • 'beforeend'

  • 'afterend'

それぞれの位置関係は以下です。

<!-- beforebegin -->

<element>
<!-- afterbegin -->
<child>Text</child>
<!-- beforeend -->
</element>
<!-- afterend -->


サンプル

先ほどと同じように以下のようなHTMLとJavaScriptコードがあったとします。


HTML

<div id="contentBlock">

<button id="clickButton">Click Here</button>
</div>


JavaScript

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

clickButton.addEventListener('click', function () {
alert('Alert!');
});

では、button要素の前に insertAdjacentHTML を使用して文字列を追加してみます。


JavaScript

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

contentBlock.insertAdjacentHTML('afterbegin', '<b>Test:</b>');

見た目的には innerHTML の時と変わりませんが、button要素のイベントが残ったままです。


insertAdjacentHTMLinnerHTML よりも処理が速い

MDN にも


余分なシリアル化のステップを回避できる分、 innerHTML への代入による直接的な操作よりもはるかに高速な動作となります。


とあります。

簡単に計測してみます。


JavaScript

function timeTest() {

var
div01 = document.createElement('div'),
div02 = document.createElement('div'),
i;

console.time('innerHTML');
for (i = 0; i < 1000; i++) {
div01.innerHTML = div01.innerHTML + 'test';
}
console.timeEnd('innerHTML');

console.time('insertAdjacentHTML');
for (i = 0; i < 1000; i++) {
div02.insertAdjacentHTML('beforeend', 'test');
}
console.timeEnd('insertAdjacentHTML');
}


結果は Chrome 61 では以下でした。(10回実行したうちのスコアがいいもの)

innerHTML: 35.122802734375ms

insertAdjacentHTML: 3.9697265625ms

10倍近い差があるみたいです。

おそらく innerHTML ではDOMツリーの再構築の負担が大きいものと思われます。


おまけ:要素を空っぽにしたいのなら textContent

とある要素の中身を空っぽにしたいのなら innerHTML よりも textContent の方がパフォーマンスはいいです。


JavaScript

document.getElementById('foo').textContent = '';



おまけ:HTML要素そのものを挿入したいなら insertAdjacentElement

文字列ではなく要素を挿入したいのなら insertAdjacentElement もありますよというお話。

Element.insertAdjacentElement() - Web API インターフェイス | MDN

第2引数が HTMLElement になるだけで基本は insertAdjacentHTML と変わりません。


JavaScript

var

contentBlock = document.getElementById('contentBlock'),
insetElement = document.createElement('b');

insetElement.textContent = 'Test:';

contentBlock.insertAdjacentElement('afterbegin', insetElement);