私は次のようにelement.innerHTML += ...
を使用してものを追加しないように言われました:
var str = "<div>hello world</div>";
var Elm = document.getElementById("targetID");
Elm.innerHTML += str; //not a good idea?
何が問題なのですか?、他にどのような選択肢がありますか?
innerHTML
が設定されるたびに、HTMLを解析し、DOMを構築し、ドキュメントに挿入する必要があります。これには時間がかかります。
たとえば、Elm.innerHTML
には数千のdiv、テーブル、リスト、画像などがあり、.innerHTML += ...
は、パーサーにそのすべてを再解析させます。これは、すでに構築されているDOM要素への参照を壊し、他の混乱を引き起こす可能性もあります。実際には、最後に1つの新しい要素を追加するだけです。
appendChild
を呼び出すだけの方が良いでしょう:
var newElement = document.createElement('div');
newElement.innerHTML = '<div>Hello World!</div>';
Elm.appendChild(newElement);
この方法では、Elm
の既存のコンテンツは再度解析されません。
注: [一部の]ブラウザは、+=
演算子。既存のコンテンツを再解析しません。私はこれを研究していません。
はい、_Elm.innerHTML += str;
_は非常に悪い考えです。
完璧な代替手段としてElm.insertAdjacentHTML( 'beforeend', str )
を使用してください。
典型的な「ブラウザはDOMを再構築する必要があります」という答えは、実際には正義の質問を行いません。
最初に、ブラウザはElmの下の各要素、各プロパティ、およびすべてのテキストとコメントとプロセスノードを調べ、それらをエスケープして文字列を作成する必要があります。
次に、長い文字列を追加します。このステップは大丈夫です。
3番目に、innerHTMLを設定すると、ブラウザーは、通過したばかりのすべての要素、プロパティ、およびノードを削除する必要があります。
次に、文字列を解析し、破棄したばかりのすべての要素、プロパティ、およびノードから構築して、ほとんど同一の新しいDOMフラグメントを作成します。
最後に、新しいノードを接続し、ブラウザは全体をレイアウトする必要があります。これは回避可能かもしれません(下の代替案を参照)が、追加されたノードにレイアウトが必要な場合でも、古いノードでは、フレッシュから再計算されるのではなく、レイアウトプロパティがキャッシュされます。
しかし、まだ完了していません!ブラウザは、alljavascript変数をスキャンして古いノードをリサイクルする必要もあります。
問題点:
一部のプロパティはHTMLに反映されない場合があります。たとえば、_<input>
_の現在の値は失われ、HTMLの初期値にリセットされます。
古いノードにイベントハンドラがある場合、それらは破棄され、すべてを再接続する必要があります。
Jsコードが古いノードを参照している場合、それらは破棄されず、代わりに孤立します。これらはドキュメントに属しますが、DOMツリーには含まれなくなりました。コードがそれらにアクセスすると、何も起こらないか、エラーがスローされる場合があります。
どちらの問題も、jsプラグインには不向きであることを意味します。プラグインはハンドラーをアタッチしたり、古いノードを記憶したり、メモリリークを引き起こす可能性があります。
InnerHTMLを使用してDOM操作を行う習慣を身に付けた場合、誤ってプロパティを変更したり、望まない他の操作を行ったりする可能性があります。
ノードが多いほど、これは非効率的であり、バッテリージュースが無駄になります。
要するに、それは非効率的であり、エラーを起こしやすく、単に怠け者であり、情報がありません。
最良の代替案は _Element.insertAdjacentHTML
_であり、他の回答では言及されていません:
Elm.insertAdjacentHTML( 'beforeend', str )
InnerHTMLの問題のない、ほぼ同じコード。再構築、ハンドラーの損失、入力のリセット、メモリの断片化の減少、悪い習慣、要素の手動作成と割り当てはありません。
プロパティを含む1行の要素にHTML文字列を挿入できます。また、yowが複合要素と複数の要素を挿入することもできます。その速度は 最適化 -Mozillaのテストでは150倍高速です。
誰かがそれがクロスブラウザではないと言った場合、HTML5 標準 であり、 すべてのブラウザ で利用できるのでとても便利です。
_
Elm.innerHTML+=
_を二度と書かないでください。
代替は.createElement()
、_.textContent
_、および.appendChild()
です。 _+=
_を追加することは、大量のデータを扱う場合にのみ問題になります。
デモ:http://jsfiddle.net/ThinkingStiff/v6WgG/
_var Elm = document.getElementById( 'targetID' ),
div = document.createElement( 'div' );
div.textContent = 'goodbye world';
Elm.appendChild( div );
_
_<div id="targetID">hello world</div>
_
ユーザーがIEの古いバージョンを使用している場合(または新しいバージョンも試していない場合)、td
のinnerHTMLで問題が発生します。 IEのテーブル要素は読み取り専用、tsk tsk tskです。
InnerHTML chromeはonclickイベントを失います jsFiddle
var blah = document.getElementById('blah');
var div = document.createElement('button');
div.style['background-color'] = 'black';
div.style.padding = '20px;';
div.style.innerHTML = 'a';
div.onclick = () => { alert('wtf');};
blah.appendChild(div);
// Uncomment this to make onclick stop working
blah.innerHTML += ' this is the culprit';
<div id="blah">
</div>
マイクの答えはおそらくより良いものですが、別の考慮事項は、文字列を扱っているということです。また、特に一部の古いブラウザでは、JavaScriptでの文字列の連結が非常に遅くなる可能性があります。 HTMLの小さなフラグメントを連結しているだけの場合は、おそらく目立たないでしょうが、繰り返しページに何かを追加しているページの大部分がある場合は、ブラウザで目立った一時停止が発生する可能性があります。
_innerHTML += ...
_(コンテンツの更新)を_innerHTML = ...
_(コンテンツの再生成)に変更すると、非常に高速なコードが得られます。 _+=
_の最も遅い部分がDOMコンテンツを文字列として読み込んでいるように見えます(文字列をDOMに変換しません)
innerHTML
を使用することの欠点は、古いコンテンツイベントハンドラーを失うことです。ただし、タグ引数を使用してこれを省略することができます。 <div onclick="yourfunc(event)">
は、小規模プロジェクトでは acceptable です
パフォーマンステストを行いました [〜#〜] here [〜#〜] Chrome、Firefox、Safariで(2019 5月)(マシンで実行できますが、我慢してください-5分ほどかかります)
_function up() {
var container = document.createElement('div');
container.id = 'container';
container.innerHTML = "<p>Init <span>!!!</span></p>"
document.body.appendChild(container);
}
function down() {
container.remove()
}
up();
// innerHTML+=
container.innerHTML += "<p>Just first <span>text</span> here</p>";
container.innerHTML += "<p>Just second <span>text</span> here</p>";
container.innerHTML += "<p>Just third <span>text</span> here</p>";
down();up();
// innerHTML += str
var s='';
s += "<p>Just first <span>text</span> here</p>";
s += "<p>Just second <span>text</span> here</p>";
s += "<p>Just third <span>text</span> here</p>";
container.innerHTML += s;
down();up();
// innerHTML = innerHTML+str
var s=container.innerHTML+'';
s += "<p>Just first <span>text</span> here</p>";
s += "<p>Just second <span>text</span> here</p>";
s += "<p>Just third <span>text</span> here</p>";
container.innerHTML = s;
down();up();
// innerHTML = str
var s="<p>Init <span>!!!</span></p>";
s += "<p>Just first <span>text</span> here</p>";
s += "<p>Just second <span>text</span> here</p>";
s += "<p>Just third <span>text</span> here</p>";
container.innerHTML = s;
down();up();
// insertAdjacentHTML str
var s='';
s += "<p>Just first <span>text</span> here</p>";
s += "<p>Just second <span>text</span> here</p>";
s += "<p>Just third <span>text</span> here</p>";
container.insertAdjacentHTML("beforeend",s);
down();up();
// insertAdjacentHTML
container.insertAdjacentHTML("beforeend","<p>Just first <span>text</span> here</p>");
container.insertAdjacentHTML("beforeend","<p>Just second <span>text</span> here</p>");
container.insertAdjacentHTML("beforeend","<p>Just third <span>text</span> here</p>");
down();up();
// appendChild
var p1 = document.createElement('p');
p1.innerHTML = 'Just first <span>text</span> here';
var p2 = document.createElement('p');
p2.innerHTML = 'Just second <span>text</span> here';
var p3 = document.createElement('p');
p3.innerHTML = 'Just third <span>text</span> here';
container.appendChild(p1);
container.appendChild(p2);
container.appendChild(p3);
_
_b {color: red}
_
_<b>This snippet NOT test anythig - only presents code used in tests</b>
_
innerHTML +=
_が最も遅いソリューションでした。innerHTML = str
_および _insertAdjacentHTML str
_ (最速)でしたinnerHTML = innerHTML +str
_を詳しく見て、_innerHTML = str
_と比較すると、_innerHTML +=
_の最も遅い部分は[〜#〜] reading [〜#〜]文字列としてのDOMコンテンツ(文字列をDOMに変換しない)createElement
/appendChild
は中速ソリューションです