更好的是,通过 DOM 函数附加新元素,或附加带有 HTML 标签的字符串?

Posted

技术标签:

【中文标题】更好的是,通过 DOM 函数附加新元素,或附加带有 HTML 标签的字符串?【英文标题】:What is better, appending new elements via DOM functions, or appending strings with HTML tags? 【发布时间】:2012-01-17 17:04:08 【问题描述】:

我已经看到了一些向 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);

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

【问题讨论】:

谢谢,已修复。太习惯用jQuery写了。 innerHTML('&lt;p&gt;Here is a brand new paragraph!&lt;/p&gt;'); 应该是innerHTML = '&lt;p&gt;Here is a brand new paragraph!&lt;/p&gt;'; 我认为? 这里的各种答案:innerHTML 肯定更快。这是旧浏览器 (IE) 的误报。 document.createElement 现在在许多浏览器中进行了高度优化。见:jsperf.com/dom-table-generation 另外有趣的是 OWASP 的 DOM 代码“备忘单”(谴责 innerHTML):owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet @MattMcDonald - 我同意 Nickolay 的观点;这不是一个很有代表性的例子。看到这个:jsperf.com/innerhtml-vs-w3c-dom 【参考方案1】:

一些注意事项:

在 IE 中使用 innerHTML 更快,但在 chrome + firefox 中更慢。 Here's one benchmark 用一组不断变化的&lt;div&gt;s + &lt;p&gt;s 来展示这一点; here's a benchmark 显示这个常量,简单的 &lt;table&gt;

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

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

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

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

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

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)或提供来源。我不清楚哪个实际上更快,并且有一个基准链接表明它在现代浏览器中并不总是更快。请参阅 Matt McDonald 对该问题的评论。 @Nickolay - 查看我的编辑。 innerHTML 在更复杂的输入上似乎确实要快得多。 感谢您花时间创建一个足够复杂的示例来证实我的怀疑! @Nickolay 链接的基准测试有问题(导致 innerHTML 版本替换了以前的基准循环内容,但 DOM 版本创建了一个不断增长的文档),这使得 DOM 看起来比实际慢。修复后,innerHTML 版本在 FF 和 chrome 中速度较慢,但​​在 IE11 中仍然更快。 “但请注意,使用 innerHTML 会从文档中分离所有现有的 DOM 节点。”这种说法具有令人难以置信的误导性。仅当您在 document.body 对象上使用 innerHTML 时,该语句才成立。如果您更改文档中某个 div 的 innerHTML,则只会分离该 div 中的 DOM 节点。【参考方案2】:

有许多不同之处:

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

综合以上,看来一个实际的结论可能是:

如果您不介意 innerHTML 有点限制(仅完全替换以目标元素为根的 DOM 子树),并且您不会因注入用户提供的内容而面临漏洞风险,请使用它.否则,请使用 DOM。

【讨论】:

只是一般性评论,不是针对您,而是针对第 1 点。每次我听到开发人员说他永远不会打破标准以及他需要学习的第二句话时,我都会发笑如何跳出框框思考...... @ItayMoav:恕我直言,“从不”打破标准的人“从不”与现实生活中的客户和截止日期合作。但我也认为,将“跳出框框思考”与我们一次又一次看到的“无论如何,这似乎有效”的心态联系起来有点危险。 这就是经验应该发挥作用的地方。帮助我们选择正确的工具。此外,这种心态确保我有足够的工作,还有我盘子里的食物:-D innerHTML ;) 将 HTML 大写【参考方案3】:

根据this benchmark data,使用innerHTML 将比创建DOM 元素更快地获得结果。使用旧版 IE 时尤其明显。

【讨论】:

【参考方案4】:

虽然这是一个旧线程,但没有提到的一件事是虽然innerHTML 可以更快,但应该小心。使用innerHTML 将渲染被修改元素的每个子元素,无论新旧。因此,单个 innerHTML 分配比 DOM 创建/附加更快(稍微),但多个 innerHTML 肯定会更慢。

例如:

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

将比

慢近 5 倍
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 在附加任何具有现有子节点的容器时会降低性能,尤其是那些具有大量子节点的容器。

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

除非性能差异很大,否则我总是更喜欢可读性。在这种一次性的情况下,这可能是一个微小的差异。

在这种一次性的情况下,设置innerHTML 属性将最容易阅读。

但如果您在 javascript 中进行大量程序化内容生成,那么 DOM 选项会更简洁、更易于阅读和理解。

示例:

比较这个innerHTML代码:

http://jsfiddle.net/P8m3K/1/

// Takes input of a value between 1 and 26, inclusive,
// and converts it to the appropriate character
function alphaToChar(alpha)

    return String.fromCharCode('a'.charCodeAt() + alpha - 1);


var content = "<ul>";
for(i = 0; i < 10; ++i)

    content += "<li>";
    for(j = 1; j <= 26; ++j)
    
        content += "<a href=\"" + alphaToChar(j) + ".html\">"
            + alphaToChar(j)
            + "</a>";
    
    content += "</li>";

document.getElementById("foo").innerHTML = content;

到这个 DOM 代码:

http://jsfiddle.net/q6GB8/1/

// Takes input of a value between 1 and 26, inclusive,
// and converts it to the appropriate character
function alphaToChar(alpha)

    return String.fromCharCode('a'.charCodeAt() + alpha - 1);


var list = document.createElement("ul");
for(i = 0; i < 10; ++i)

    var item = document.createElement("li");
    for(j = 1; j <= 26; ++j)
    
        var link = document.createElement("a");
        link.setAttribute("href", alphaToChar(j) + ".html");
        link.innerText = alphaToChar(j);
        item.appendChild(link);
    
    list.appendChild(item);

document.getElementById("foo").appendChild(list);

在这个级别上,它们开始变得非常相似。

但是 DOM 代码将更容易维护,并且您不太可能犯难以诊断的拼写错误或错误,例如省略结束标记。您的元素要么在文档中,要么不在。

对于更复杂的场景(例如构建树状菜单),您可能会在 DOM 代码方面取得领先。 在您必须将多种类型的内容附加在一起以构建具有更多异构内容的文档的情况下,它变成了灌篮。您不必确保在调用父附加代码之前调用您的子附加代码。 对于添加、删除或修改现有静态内容的场景,DOM 通常会胜出。

如果您开始进行复杂的 DOM 修改(我提到的最后一件事),您肯定会想要查看一个围绕 DOM 修改构建的库,like jQuery。

【讨论】:

我从您对使用 jQuery 的 OP 的评论中得知。我只是为将来发现您问题的人提到的:)

以上是关于更好的是,通过 DOM 函数附加新元素,或附加带有 HTML 标签的字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 DOM 元素附加到动态新添加的 DOM 元素

如何使用 Jquery 或 Javascript 定位附加元素,或者如何将该附加元素添加到 DOM?

在 jQuery.each 中附加元素时出现错误

在 DOM 中的所有元素上附加 click 事件的事件处理程序

DOM 无法将节点附加到 DOMNodeList (PHP 7.3) 中的元素

遍历字典列表并 1) 将流值与流列元素进行比较 2) 如果匹配,则附加一个带有数据的新列表