createElement比innerHTML的优点?

实际上,使用createElement而不是innerHTML有什么优势? 我在问,因为我确信使用innerHTML在性能和代码可读性/可维护性方面更有效率,但是我的队友已经决定使用createElement作为编码方法。 我只是想了解createElement如何更有效率。

除了安全性之外,使用createElement而不是修改innerHTML (而不是抛弃已经存在的内容并replace它)有几个好处,就像Pekka已经提到的那样:

附加元素时,保留对DOM元素的现有引用

当附加到(或以其他方式修改) innerHTML ,该元素内的所有DOM节点都必须重新parsing并重新创build。 如果保存了对节点的任何引用,它们将基本上是无用的,因为它们不再是显示出来的。

保留附加到任何DOM元素的事件处理程序

这实际上只是最后一个特例(尽pipe很普遍)。 设置innerHTML不会自动将事件处理程序重新附加到它创build的新元素,因此您必须自己跟踪它们并手动添加它们。 事件代表团可以在某些情况下消除这个问题。

在某些情况下可能会更简单/更快

如果您正在做大量的添加,您绝对不想重置innerHTML因为虽然对于简单更改更快,但反复重新parsing和创build元素会更慢。 解决这个问题的方法是在string中构buildHTML,并在完成后设置innerHTML 。 根据情况,string操作可能会比创build元素和附加它们慢。

此外,string操作代码可能更复杂(特别是如果你想要它是安全的)。

下面是我使用的一个函数,它使得使用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> 

虽然innerHTML可能会更快,但我不同意在可读性或维护方面更好。 将所有内容放在一个string中可能会更短,但更短的代码不一定总是更容易维护。

当需要创builddynamicDOM元素时,string连接并不会缩放,因为加号和引号的打开和closures变得很难跟踪。 考虑这些例子:

生成的元素是一个div,其内容是dynamic的两个内部跨度。 其中一个class级名称(战士)也是dynamic的。

 <div> <span class="person warrior">John Doe</span> <span class="time">30th May, 2010</span> </div> 

假定已经定义了以下variables:

 var personClass = 'warrior'; var personName = 'John Doe'; var date = '30th May, 2010'; 

使用innerHTML并将所有东西混合成单个string,我们得到:

 someElement.innerHTML = "<div><span class='person " + personClass + "'>" + personName + "</span><span class='time'>" + date + "</span></div>"; 

上面的混乱可以通过使用stringreplace来清除,以避免每次打开和closuresstring。 即使对于简单的文本replace,我更喜欢使用replace而不是string连接。

这是一个简单的函数,它接受一个键和replace值的对象,并将其replace为string。 它假定这些键的前缀是$ ,表示它们是一个特殊的值。 它不会做任何转义或处理边缘的情况下$出现在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 }); 

用户bobince在对jQuery的批评中提出了很多缺点。

…另外,你可以通过说$(''+ message +''),而不必与document.createElement('div')和文本节点。 万岁! 只有…坚持下去。 你还没有逃脱那个HTML,并且可能刚刚创build了一个跨站点脚本的安全漏洞,这次只在客户端。 而且花了这么长时间清理PHP之后,在服务器端也使用htmlspecialchars。 多可惜。 啊,没有人真正关心正确性或安全性,是吗?

jQuery并不完全是因为这个原因。 毕竟,innerHTML属性已经有好几年了,已经比DOM更受欢迎了。 但图书馆确实鼓励这种编码风格。

至于性能: InnerHTML肯定会变慢,因为它需要被parsing并在内部转换成DOM元素(可能使用createElement方法)。

根据@Pointy提供的quirksmode基准 ,InnerHTML在所有浏览器中速度更快。

至于可读性和易用性,在大多数项目的任何一天的任何一天,您都会发现我select了innerHTML over createElement 。 但是正如你所看到的,对于createElement来讲,有很多要点。

如果要在代码中保留引用,则应该使用createElement。 InnerHTML有时可能会创build一个很难察觉的错误。

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)你不能改变颜色或其他任何东西,因为在上面的行中你添加了一些内容,所有东西都被重新创build,你可以访问不存在的东西。 为了改变它,你必须再次getElementById

你需要记住,它也影响任何事件。 你需要重新申请活动。

InnerHTML是伟大的,因为它更快,最容易阅读,但你必须小心谨慎使用它。 如果你知道你在做什么,你会没事的。