Javascript createElement 相对于innerHTML 的优势?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2946656/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Advantages of createElement over innerHTML?
提问by oninea
In practice, what are the advantages of using createElement over innerHTML? I am asking because I'm convinced that using innerHTML is more efficient in terms of performance and code readability/maintainability but my teammates have settled on using createElement as the coding approach. I just wanna understand how createElement can be more efficient.
在实践中,使用 createElement 比使用 innerHTML 有什么优势?我之所以这么问是因为我确信使用 innerHTML 在性能和代码可读性/可维护性方面更有效,但我的团队成员已决定使用 createElement 作为编码方法。我只是想了解 createElement 如何更有效。
采纳答案by Matthew Crumley
There are several advantages to using createElementinstead of modifying innerHTML(as opposed to just throwing away what's already there and replacing it) besides safety, like Pekka already mentioned:
除了安全之外,使用createElement而不是修改innerHTML(而不是扔掉已经存在的东西并替换它)还有几个优点,就像 Pekka 已经提到的:
Preserves existing references to DOM elements when appending elements
附加元素时保留对 DOM 元素的现有引用
When you append to (or otherwise modify) innerHTML, all the DOM nodes inside that element have to be re-parsed and recreated. If you saved any references to nodes, they will be essentially useless, because they aren't the ones that show up anymore.
当您附加到(或以其他方式修改)时innerHTML,必须重新解析和重新创建该元素内的所有 DOM 节点。如果您保存了对节点的任何引用,它们基本上将毫无用处,因为它们不再出现。
Preserves event handlers attached to any DOM elements
保留附加到任何 DOM 元素的事件处理程序
This is really just a special case (although common) of the last one. Setting innerHTMLwill not automatically reattach event handlers to the new elements it creates, so you would have to keep track of them yourself and add them manually. Event delegation can eliminate this problem in some cases.
这实际上只是最后一个的一个特例(虽然很常见)。设置innerHTML不会自动将事件处理程序重新附加到它创建的新元素,因此您必须自己跟踪它们并手动添加它们。在某些情况下,事件委托可以消除这个问题。
Could be simpler/faster in some cases
在某些情况下可能更简单/更快
If you are doing lots of additions, you definitely don't want to keep resetting innerHTMLbecause, although faster for simple changes, repeatedly re-parsing and creating elements would be slower. The way to get around that is to build up the HTML in a string and set innerHTMLonce when you are done. Depending on the situation, the string manipulation could be slower than just creating elements and appending them.
如果您要进行大量添加,则绝对不想继续重置,innerHTML因为尽管对于简单更改会更快,但重复重新解析和创建元素会更慢。解决这个问题的方法是在字符串中构建 HTML 并innerHTML在完成后设置一次。根据情况,字符串操作可能比创建元素并附加它们要慢。
Additionally, the string manipulation code may be more complicated (especially if you want it to be safe).
此外,字符串操作代码可能更复杂(特别是如果您希望它是安全的)。
Here's a function I use sometimes that make it more convenient to use createElement.
这是我有时使用的一个功能,它使使用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;
}
If you call it like this:
如果你这样称呼它:
make(["p", "Here is a ", ["a", { href:"http://www.google.com/" }, "link"], "."]);
you get the equivalent of this HTML:
你得到相当于这个 HTML:
<p>Here is a <a href="http://www.google.com/">link</a>.</p>
回答by Anurag
While innerHTMLmay be faster, I don't agree that it is better in terms of readability or maintenance. It may be shorter to put everything in one string, but shorter code is not always necessarily more maintainable.
虽然innerHTML可能更快,但我不同意它在可读性或维护方面更好。将所有内容放在一个字符串中可能会更短,但更短的代码并不总是更易于维护。
String concatenation just does not scale when dynamic DOM elements need to be created as the plus' and quote openings and closings becomes difficult to track. Consider these examples:
当需要创建动态 DOM 元素时,字符串连接不会扩展,因为加号和引号的开头和结尾变得难以跟踪。考虑以下示例:
The resulting element is a div with two inner spans whose content is dynamic. One of the class names (warrior) inside the first span is also dynamic.
生成的元素是一个具有两个内部跨度的 div,其内容是动态的。第一个跨度内的一个类名(战士)也是动态的。
<div>
<span class="person warrior">John Doe</span>
<span class="time">30th May, 2010</span>
</div>
Assume the following variables are already defined:
假设已经定义了以下变量:
var personClass = 'warrior';
var personName = 'John Doe';
var date = '30th May, 2010';
Using just innerHTML and mashing everything into a single string, we get:
仅使用 innerHTML 并将所有内容混合成一个字符串,我们得到:
someElement.innerHTML = "<div><span class='person " + personClass + "'>" + personName + "</span><span class='time'>" + date + "</span></div>";
The above mess can be cleaned up with using string replacements to avoid opening and closing strings every time. Even for simple text replacements, I prefer using replaceinstead of string concatenation.
可以使用字符串替换来清理上述混乱,以避免每次打开和关闭字符串。即使对于简单的文本替换,我也更喜欢使用replace而不是字符串连接。
This is a simple function that takes an object of keys and replacement values and replaces them in the string. It assumes the keys are prefixed with $to denote they are a special value. It does not do any escaping or handle edge cases where $appears in the replacement value etc.
这是一个简单的函数,它接受一个键和替换值的对象并在字符串中替换它们。它假设键以 为前缀$来表示它们是一个特殊值。它不做任何转义或处理$出现在替换值等中的边缘情况。
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;
?This can be improved by separating the attributes, text, etc. while constructing the object to get more programmatic control over the element construction. For example, with MooTools we can pass object properties as a map. This is certainly more maintainable, and I would argue more readable as well. jQuery 1.4 uses a similar syntax to pass a map for initializing DOM objects.
? 这可以通过在构造对象时分离属性、文本等来改进,以获得对元素构造的更多编程控制。例如,使用 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]);
I wouldn't call the pure DOM approach below to be any more readable than the ones above, but it's certainly more maintainable because we don't have to keep track of opening/closing quotes and numerous plus signs.
我不会称下面的纯 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);
The most readable version would most likely result from using some sort of JavaScript templating.
最易读的版本很可能来自使用某种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
});
回答by Pekka
User bobinceputs a number of cons very, very well in his critique of jQuery.
用户bobince在他对 jQuery 的批评中提出了一些非常非常好的缺点。
... Plus, you can make a div by saying $(''+message+'') instead of having to muck around with document.createElement('div') and text nodes. Hooray! Only... hang on. You've not escaped that HTML, and have probably just created a cross-site-scripting security hole, only on the client side this time. And after you'd spent so long cleaning up your PHP to use htmlspecialchars on the server-side, too. What a shame. Ah well, no-one really cares about correctness or security, do they?
jQuery's not wholly to blame for this. After all, the innerHTML property has been about for years, and already proved more popular than DOM. But the library certainly does encourage that style of coding.
...另外,您可以通过说 $(''+message+'') 来创建一个 div,而不必再纠结于 document.createElement('div') 和文本节点。万岁!只是……坚持。您没有转义该 HTML,并且可能刚刚创建了一个跨站点脚本安全漏洞,这次仅在客户端。在您花了很长时间清理 PHP 以在服务器端也使用 htmlspecialchars 之后。多可惜。嗯,没有人真正关心正确性或安全性,是吗?
jQuery 不完全归咎于此。毕竟,innerHTML 属性已经存在多年,并且已经证明比 DOM 更流行。但图书馆确实鼓励这种编码风格。
As for performance: InnerHTML is most definitely going to be slower, because it needs to be parsed and internally converted into DOM elements (maybe using the createElementmethod).
至于性能:InnerHTML 肯定会更慢,因为它需要被解析并在内部转换为 DOM 元素(可能使用该createElement方法)。
InnerHTML is faster in all browsers according to the quirksmode benchmarkprovided by @Pointy.
根据@Pointy 提供的quirksmode 基准,InnerHTML在所有浏览器中都更快。
As for readabilityand ease of use, you will find me choosing innerHTMLover createElementany day of the week in most projects. But as you can see, there are many points speaking for createElement.
至于可读性和易用性,你会发现我选择innerHTML在createElement一周的任何一天,大多数项目。但正如你所看到的,有很多观点可以说明createElement。
回答by Morfidon
You should use createElement if you want to keep references in your code. InnerHTML can sometimes create a bug that is hard to spot.
如果您想在代码中保留引用,您应该使用 createElement。InnerHTML 有时会产生难以发现的错误。
HTML code:
HTML代码:
<p id="parent">sample <span id='test'>text</span> about anything</p>
JS code:
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) you can change the color
1)你可以改变颜色
2) you can't change color or whatever else anymore, because in the line above you added something to innerHTML and everything is re-created and you have access to something that doesn't exist anymore. In order to change it you have to again getElementById.
2)你不能再改变颜色或其他任何东西,因为在上面的行中,你向innerHTML添加了一些东西,一切都被重新创建,你可以访问不再存在的东西。为了改变它,你必须再次getElementById。
You need to remember that it also affects any events. You need to re-apply events.
您需要记住,它也会影响任何事件。您需要重新应用事件。
InnerHTML is great, because it is faster and most time easier to read but you have to be careful and use it with caution. If you know what you are doing you will be OK.
InnerHTML 很棒,因为它更快,而且大多数时候更容易阅读,但您必须小心谨慎地使用它。如果你知道你在做什么,你会没事的。
回答by CloudBranch
Template literals (Template strings) is another option.
模板文字(模板字符串)是另一种选择。
const container = document.getElementById("container");
const item_value = "some Value";
const item = `<div>${item_value}</div>`
container.innerHTML = item;

