我被告知不要使用element.innerHTML += ...
这样的方式附加内容:
var str = "<div>hello world</div>";
var elm = document.getElementById("targetID");
elm.innerHTML += str; //not a good idea?
它有什么问题?,我还有什么其他选择?
我被告知不要使用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 元素的引用并导致其他混乱。实际上,您要做的就是在末尾添加一个新元素。
最好只调用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 下的每个元素、它们的每个属性以及它们的所有文本、注释和流程节点,并将它们转义以构建一个字符串。
然后你有一个长字符串,你附加到它。这一步没问题。
第三,当您设置innerHTML 时,浏览器必须删除它刚刚通过的所有元素、属性和节点。
然后它解析字符串,从它刚刚销毁的所有元素、属性和节点构建,以创建一个几乎相同的新 DOM 片段。
最后它附加新节点,浏览器必须布局整个事情。这可能是可以避免的(请参阅下面的替代方案),但即使附加节点需要布局,旧节点也会缓存其布局属性,而不是从新节点重新计算。
但它还没有完成!浏览器还必须通过扫描所有javascript 变量来回收旧节点。
问题:
某些属性可能不会被 HTML 反映,例如 的当前值<input>
将丢失并重置为 HTML 中的初始值。
如果旧节点上有任何事件处理程序,它们将被销毁,您必须重新附加所有这些事件处理程序。
如果您的 js 代码引用了任何旧节点,它们不会被销毁,而是会被孤立。它们属于文档但不再在 DOM 树中。当您的代码访问它们时,可能什么也不会发生,也可能会引发错误。
这两个问题都意味着它对 js 插件不友好——插件可能会附加处理程序,或者保留对旧节点的引用并导致内存泄漏。
如果您养成了使用 innerHTML 进行 DOM 操作的习惯,您可能会不小心更改属性或做其他您不想做的事情。
您拥有的节点越多,效率越低,电池电量就越多。
简而言之,它效率低下,容易出错,它只是懒惰和不知情。
最好的选择是Element.insertAdjacentHTML
,我还没有看到其他答案提到:
elm.insertAdjacentHTML( 'beforeend', str )
几乎相同的代码,没有innerHTML 的问题。没有重建,没有处理程序丢失,没有输入重置,更少的内存碎片,没有坏习惯,没有手动元素创建和分配。
它允许您将 html 字符串注入一行中的元素,包括属性,甚至允许 yow 注入复合元素和多个元素。它的速度得到了优化——在 Mozilla 的测试中,它的速度提高了150倍。
如果有人告诉你它不是跨浏览器,它非常有用,它是 HTML5标准并且可用于所有浏览器。
永远不要再写
elm.innerHTML+=
了。
如果您将innerHTML += ...
(更新内容)更改为innerHTML = ...
(重新生成内容),那么您将获得非常快的代码。看起来最慢的部分+=
是将 DOM 内容作为字符串读取(而不是将字符串转换为 DOM)
使用的缺点innerHTML
是你失去了旧的内容事件处理程序 - 但是你可以使用标签参数来省略这个,例如<div onclick="yourfunc(event)">
这在小项目中是可以接受的
我做了性能测试,这里在Chrome,Firefox和Safari(2019日)(你可以在你的机器上运行它们,但要有耐心-它需要约5分钟)
innerHTML +=
是最慢的解决方案。appendChild
- 它比第二个快速解决方案快约 38%,但它非常不方便。令人惊讶的是,在 FirefoxappendChild
上比innerHTML =
.insertAdjacentHTML str
和innerHTML = str
innerHTML = innerHTML +str
并与innerHTML = str
它进行比较,看起来最慢的部分innerHTML +=
是将DOM 内容作为字符串读取(而不是将字符串转换为 DOM)appendChild
用innerHTML=
实际上比纯慢innerHTML=
替代方案是.createElement()
、.textContent
、 和.appendChild()
。+=
如果您要处理大量数据,附加 with只是一个问题。
演示: 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(或者也可能是新版本,还没有尝试过),a 上的 innerHTMLtd
会导致问题。IE中的表格元素是只读的,tsk tsk tsk。