実際には、innerHTMLよりもcreateElementを使用する利点は何ですか?パフォーマンスとコードの可読性/保守性の点でinnerHTMLを使用する方が効率的であると確信しているので、質問していますが、チームメートはコーディングアプローチとしてcreateElementを使用することに決めました。createElementをより効率的にする方法を理解したいだけです。
5 に答える
createElement
すでに述べたように、安全性のほかに、変更する代わりに使用することにはいくつかの利点がありますinnerHTML
(すでにそこにあるものを捨てて置き換えるのではなく):
要素を追加するときに、DOM要素への既存の参照を保持します
に追加(またはその他の方法で変更)する場合innerHTML
、その要素内のすべてのDOMノードを再解析して再作成する必要があります。ノードへの参照を保存した場合、それらはもう表示されないため、本質的に役に立たなくなります。
DOM要素にアタッチされたイベントハンドラーを保持します
これは実際には、最後のケースの(一般的ではありますが)特殊なケースです。設定innerHTML
によって、作成された新しい要素にイベントハンドラーが自動的に再アタッチされないため、イベントハンドラーを自分で追跡し、手動で追加する必要があります。イベントの委任により、場合によってはこの問題を解消できます。
場合によっては、より単純/高速になる可能性があります
多くの追加を行う場合は、リセットを続けたくないことは間違いありません。innerHTML
単純な変更の場合は高速ですが、要素の再解析と作成を繰り返すと速度が低下するためです。これを回避する方法は、HTMLを文字列で作成し、innerHTML
完了したら一度設定することです。状況によっては、文字列の操作は、要素を作成して追加するよりも遅くなる可能性があります。
さらに、文字列操作コードはより複雑になる可能性があります(特に安全にしたい場合)。
これが私が時々使う関数で、使いやすくなっていますcreateElement
。
function isArray(a) {
return Object.prototype.toString.call(a) === "[object Array]";
}
function make(desc) {
if (!isArray(desc)) {
return make.call(this, Array.prototype.slice.call(arguments));
}
var name = desc[0];
var attributes = desc[1];
var el = document.createElement(name);
var start = 1;
if (typeof attributes === "object" && attributes !== null && !isArray(attributes)) {
for (var attr in attributes) {
el[attr] = attributes[attr];
}
start = 2;
}
for (var i = start; i < desc.length; i++) {
if (isArray(desc[i])) {
el.appendChild(make(desc[i]));
}
else {
el.appendChild(document.createTextNode(desc[i]));
}
}
return el;
}
あなたがそれをこのように呼ぶならば:
make(["p", "Here is a ", ["a", { href:"http://www.google.com/" }, "link"], "."]);
このHTMLに相当するものを取得します。
<p>Here is a <a href="http://www.google.com/">link</a>.</p>
ユーザーbobinceは、 jQueryに対する彼の批評に、非常に多くの短所を置いています。
...さらに、document.createElement('div')とテキストノードをいじくり回す代わりに、$('' + message +'')と言うことでdivを作成できます。やったー!ただ...ちょっと待って。あなたはそのHTMLを回避しておらず、おそらく今回はクライアント側でのみ、クロスサイトスクリプティングのセキュリティホールを作成しただけです。そして、サーバー側でもhtmlspecialcharsを使用するために、PHPのクリーンアップに長い時間を費やした後。残念だ。ええと、誰も本当に正確さやセキュリティを気にしませんか?
jQueryがこれを完全に非難しているわけではありません。結局のところ、innerHTMLプロパティは何年も前から存在しており、すでにDOMよりも人気があることが証明されています。しかし、ライブラリは確かにそのスタイルのコーディングを奨励しています。
パフォーマンスに関して:InnerHTMLは、解析して内部でDOM要素に変換する必要があるため(おそらくcreateElement
メソッドを使用して)、間違いなく遅くなります。
@Pointyが提供するquirksmodeベンチマークによると、InnerHTMLはすべてのブラウザで高速です。
読みやすさと使いやすさに関しては、ほとんどのプロジェクトで私が曜日を選択innerHTML
していることに気付くでしょう。createElement
しかし、ご覧のとおり、について話すポイントはたくさんありますcreateElement
。
速いかもしれませinnerHTML
んが、読みやすさやメンテナンスの点で優れているとは思いません。すべてを1つの文字列にまとめる方が短い場合がありますが、コードが短いほど、必ずしも保守しやすいとは限りません。
文字列の連結は、動的DOM要素を作成する必要がある場合にスケーリングされません。これは、プラス記号と引用符の開始と終了の追跡が困難になるためです。次の例を検討してください。
結果の要素は、コンテンツが動的である2つの内部スパンを持つdivです。最初のスパン内のクラス名の1つ(戦士)も動的です。
<div>
<span class="person warrior">John Doe</span>
<span class="time">30th May, 2010</span>
</div>
次の変数がすでに定義されていると仮定します。
var personClass = 'warrior';
var personName = 'John Doe';
var date = '30th May, 2010';
innerHTMLだけを使用し、すべてを1つの文字列にマッシュすると、次のようになります。
someElement.innerHTML = "<div><span class='person " + personClass + "'>" + personName + "</span><span class='time'>" + date + "</span></div>";
上記の混乱は、文字列の置換を使用してクリーンアップし、毎回文字列を開いたり閉じたりしないようにすることができます。単純なテキスト置換の場合でもreplace
、文字列連結の代わりに使用することを好みます。
これは、キーと置換値のオブジェクトを取得し、文字列内でそれらを置換する単純な関数です。$
キーには、特別な値であることを示すために接頭辞が付いていることを前提としています。$
置換値などに現れるエッジケースのエスケープや処理は行いません。
function replaceAll(string, map) {
for(key in map) {
string = string.replace("$" + key, map[key]);
}
return string;
}
var string = '<div><span class="person $type">$name</span><span class="time">$date</span></div>';
var html = replaceAll(string, {
type: personClass,
name: personName,
date: date
});
someElement.innerHTML = html;
これは、オブジェクトを構築するときに属性やテキストなどを分離して、要素の構築をよりプログラムで制御することで改善できます。たとえば、MooToolsを使用すると、オブジェクトのプロパティをマップとして渡すことができます。これは確かにより保守可能であり、私もより読みやすいと主張します。jQuery 1.4は、同様の構文を使用して、DOMオブジェクトを初期化するためのマップを渡します。
var div = new Element('div');
var person = new Element('span', {
'class': 'person ' + personClass,
'text': personName
});
var when = new Element('span', {
'class': 'time',
'text': date
});
div.adopt([person, when]);
以下の純粋なDOMアプローチを上記のアプローチよりも読みやすくとは言いませんが、開始/終了の引用符や多数のプラス記号を追跡する必要がないため、確かに保守性が高くなります。
var div = document.createElement('div');
var person = document.createElement('span');
person.className = 'person ' + personClass;
person.appendChild(document.createTextNode(personName));
var when = document.createElement('span');
when.className = 'date';
when.appendChild(document.createTextNode(date));
div.appendChild(person);
div.appendChild(when);
最も読みやすいバージョンは、おそらく何らかのJavaScriptテンプレートを使用した結果です。
<div id="personTemplate">
<span class="person <%= type %>"><%= name %></span>
<span class="time"><%= date %></span>
</div>
var div = $("#personTemplate").create({
name: personName,
type: personClass,
date: date
});
コード内で参照を保持する場合は、createElementを使用する必要があります。InnerHTMLは、見つけるのが難しいバグを作成することがあります。
HTMLコード:
<p id="parent">sample <span id='test'>text</span> about anything</p>
JSコード:
var test = document.getElementById("test");
test.style.color = "red"; //1 - it works
document.getElementById("parent").innerHTML += "whatever";
test.style.color = "green"; //2 - oooops
1)色を変えることができます
2)上の行でinnerHTMLに何かを追加し、すべてが再作成され、もう存在しないものにアクセスできるため、色などを変更することはできません。それを変更するには、もう一度getElementByIdを取得する必要があります。
イベントにも影響することを覚えておく必要があります。イベントを再適用する必要があります。
InnerHTMLは、より速く、ほとんどの場合読みやすいので素晴らしいですが、注意して使用する必要があります。あなたが何をしているのかを知っていれば、あなたは大丈夫です。
テンプレートリテラル(テンプレート文字列)は別のオプションです。
const container = document.getElementById("container");
const item_value = "some Value";
const item = `<div>${item_value}</div>`
container.innerHTML = item;