通过 DOM 函数附加新元素,或用 HTML 标签附加字符串,哪个更好?

IT技术 javascript dom appendchild
2021-03-18 08:12:32

我见过几种不同的方法来向 DOM 添加元素。例如,最流行的似乎是

document.getElementById('foo').innerHTML ='<p>Here is a brand new paragraph!</p>';

或者

newElement = document.createElement('p');
elementText = document.createTextNode('Here is a brand new parahraph!');
newElement.appendChild(elementText);
document.getElementById('foo').appendChild(newElement);

但我不确定做任何一个的好处。关于什么时候应该完成另一个,或者其中一个只是完全错误的,是否有经验法则?

6个回答

一些注意事项:

  • innerHTML在 IE 中使用速度更快,但在 chrome + firefox 中使用速度较慢。这是一个基准,用一组不断变化的<div>s + <p>s 来显示这一点这是一个基准,显示了一个恒定的、简单的<table>.

  • 另一方面,DOM 方法是传统标准——innerHTML在 HTML5 中标准化——并且允许您保留对新创建元素的引用,以便您以后可以修改它们。

  • 因为innerHTML 快速(足够)、简洁且易于使用,所以很容易在每种情况下都依赖它。但要注意 usinginnerHTML从文档中分离所有现有的 DOM 节点这是您可以在此页面上测试的示例。

    首先,让我们创建一个函数,让我们测试一个节点是否在页面上:

    function contains(parent, descendant) {
        return Boolean(parent.compareDocumentPosition(descendant) & 16);
    }
    

    true如果parent包含,这将返回descendant像这样测试它:

    var p = document.getElementById("portalLink")
    console.log(contains(document, p)); // true
    document.body.innerHTML += "<p>It's clobberin' time!</p>";
    console.log(contains(document, p)); // false
    p = document.getElementById("portalLink")
    console.log(contains(document, p)); // true
    

    这将打印:

    true
    false
    true
    

    看起来我们的使用innerHTML应该不会影响我们对portalLink元素的引用,但确实如此。它需要再次检索才能正确使用。

“但请注意,使用 innerHTML 会将所有现有的 DOM 节点与文档分离。” 这种说法极具误导性。仅当您在 document.body 对象上使用 innerHTML 时,该语句才为真。如果您更改文档中某个 div 的 innerHTML,则只会分离该 div 中的 DOM 节点。
2021-04-24 08:12:32
@Nickolay - 请参阅我的编辑。innerHTML在更复杂的输入上似乎确实要快得多。
2021-04-26 08:12:32
感谢您花时间创建一个足够复杂的示例来证实我的怀疑!
2021-05-10 08:12:32
很好的答案,但请改写第一个声明(更快的innerHTML)或提供来源。我不清楚哪个实际上更快,并且有一个指向基准的链接,表明它在现代浏览器中并不总是更快。请参阅马特麦当劳对该问题的评论。
2021-05-11 08:12:32
@Nickolay 链接的基准测试有问题(导致 innerHTML 版本替换了之前的基准测试循环内容,但 DOM 版本创建了一个不断增长的文档),这使得 DOM 看起来比它更慢。修复后,innerHTML 版本在 FF 和 chrome 中变慢,但在 IE11 中仍然更快。
2021-05-14 08:12:32

有许多不同之处:

  1. innerHTML仅被 W3C 标准化为 HTML 5;尽管一段时间以来它已经成为所有流行浏览器的事实上的标准,但从技术上讲,在 HTML 4 中,它是一个供应商扩展,遵循标准的开发人员永远不会被发现使用。另一方面,它更方便,几乎所有浏览器都支持它。
  2. innerHTML 替换元素的当前内容(它不允许您修改它)。但同样,如果您不介意此限制,您将获得更多便利。
  3. innerHTML 经测量要快得多(诚然,该测试涉及当今尚未广泛使用的旧版本浏览器)。
  4. innerHTML如果将其设置为未正确编码的用户提供的值(例如el.innerHTML = '<script>...',则可能代表安全风险 (XSS )。

基于上述,似乎一个实际的结论可能是:

  • 如果您不介意innerHTML有点限制的事实(仅完全替换以目标元素为根的 DOM 子树)并且您不会通过注入用户提供的内容来冒漏洞风险,请使用它。否则,请使用 DOM。
只是一般性评论,不是针对您,而是针对第 1 点。每次听到开发人员说他永远不会违反标准以及在第二句话中他需要学习如何跳出框框思考时,都会让我发笑。 ..
2021-04-26 08:12:32
@ItayMoav:恕我直言,“永远”不会违反标准的人“从来没有”与现实生活中的客户和截止日期合作过。但我也认为,将“跳出框框思考”与我们一次又一次看到的“无论如何,这似乎行得通”的心态联系起来有点危险。
2021-04-26 08:12:32
这就是经验应该发挥作用的地方。帮助我们选择正确的工具。此外,这种心态确保我有足够的工作和盘子里的食物:-D
2021-05-02 08:12:32
innerHTML ;) 大写 HTML
2021-05-08 08:12:32

根据这个基准数据,您将获得innerHTML比创建 DOM 元素更快的结果使用较旧的 IE 版本时尤其明显。

虽然这是一个旧线程,但没有提到的一件事是 whileinnerHTML可以更快,但应该小心。UsinginnerHTML将渲染修改后元素的每个子元素,无论是旧元素还是新元素。因此,单个innerHTML赋值比 DOM 创建/追加更快(略),但多个赋值innerHTML肯定会更慢。

例如:

for(let i=0; i < 10; i++)
   document.body.innerHTML+='<div>some text</div>';

将比

let html = '';
for(let i=0; i < 10; i++)
   html += '<div>some text</div>';

document.body.innerHTML = html;

由于innerHTML赋值是让浏览器本地创建/附加元素,第二种方法导致 10 个元素被本地创建/附加,而第一种方法导致 55 个元素被创建/附加(和 45 个被销毁):在第一个循环中创建 1 个元素 -迭代,在第二次循环迭代中创建的 2 个元素(原始被销毁),在第三次循环迭代中创建的 3 个元素(前 2 个被销毁),依此类推。

如果innerHTML为了速度而使用,则必须确保在进行innerHTML分配之前先创建整个 html 字符串,例如创建新的 DOM 容器/元素。 innerHTML另一方面,在附加任何具有现有子节点的容器时,尤其是那些具有大量子节点的容器时,性能会下降。

第一个是直接的,更容易阅读,更少的代码并且可能更快。
第二个让你对你创建的元素有更多的控制,即使用 JS 修改新元素更容易(比如附加事件,或者只是在你的代码中使用它)。
第二种方法适用于喜欢“干净”代码的“纯粹主义者”(没有快速和肮脏)。
我说,两者都用,看看哪个更适合你,然后用它。