JavaScript innerHTML与outerHTML

28
我有以下的JavaScript代码:
// create a new article tag
var elem = document.createElement('article');

// append the article to the comments list
document.querySelector('#comments-list').appendChild(elem);

我想设置文章的内容,并为其添加一些类,因此我正在考虑两种方法:

// Option 1
// set the content using .innerHTML()
// and add the classes manually to the classList 
elem.innerHTML = "This is the comment";
elem.classList.add('comment'); 

// Option 2
// set the content and classes in one go using .outerHTML()
elem.outerHTML = "<article class='comment'>This is the comment</article>";

两者都很好,但我注意到 .innerHTML 需要在元素附加到 DOM 之前调用,而 outerHTML 需要在添加到 DOM 后调用。

我更喜欢第二种选项,因为我实际上在此 JavaScript 文件中呈现 Rails 偏见,并且存在微妙的情况,其中它是首选。

我的问题是这两种技术是否有一种比另一种更好?将元素添加到 DOM 然后再更改其 HTML 是有问题的吗?还是从性能的角度来看,在写入到 DOM 之前设置 innerHTML 更好?


1
好的,你提到了,innerHTML 可以在元素未连接到 DOM 时设置,如果它们在操作期间不更新 DOM,则大型操作往往会更快。 - Icepickle
2
设置outerHTML是毫无必要的,只需使用elem.className="comment"即可。 - dandavis
2
这是个人意见,大多数个人意见都会认为设置outerHTML很糟糕。 - epascarello
使用 innerHTML 也不应该被使用,而是应该创建… - user7951676
创建一个文本节点并将其插入到文章元素中。 - user7951676
请看一下我的答案,因为它不仅仅是一个“个人意见”,而是你选择使用哪个...! - ravo10
3个回答

21

摘自 MDN 网站:

innerHTML

  • Element.innerHTML 属性设置或获取描述元素后代的 HTML 语法。

注意: 如果一个 <div>, <span>,<noembed> 节点具有包含字符 (&), (<),(>) 的子文本节点,则 innerHTML 返回这些字符分别表示为 &amp, &lt 和 &gt。使用 Node.textContent 获取这些文本节点内容的正确副本。

outerHTML

element DOM 接口的 outerHTML 属性获取序列化的 HTML 片段,描述该元素及其后代。它可以被设置为用给定字符串解析的节点替换元素。

innerHTML vs. outerHTML :

默认情况下使用 innerHTML。这将仅替换当前引用的元素内部的内容(如果使用 "=")。如果使用 outerHTML,则也将替换所引用的元素

演示:

var h20 = document.getElementById("h20"),
    h21 = document.getElementById("h21");
var ran = false;

console.log("'h20' innerHTML (1) =", "'" + h20.innerHTML + "'", "outerHTML (1) =", "'" + h20.outerHTML + "'");
console.log("'h21' innerHTML (1) =", "'" + h21.innerHTML + "'", "outerHTML (1) =", "'" + h21.outerHTML + "'");

document.getElementById("button").onclick = evt => {
    if (ran) return false;
    
    h20.innerHTML = "<div>innerHTML</div>";
    h21.outerHTML = "<div>outerHTML</div>";
    
    console.log("'h20' innerHTML (2) =", "'" + h20.innerHTML + "'", "outerHTML (2) =", "'" + h20.outerHTML + "'");
    console.log("'h21' innerHTML (2) =", "'" + h21.innerHTML + "'", "outerHTML (2) =", "'" + h21.outerHTML + "'");
    
    ran = true
}
<button id="button">innerHTML vs. outerHTML</button>
<br>
<h2 id="h20"></h2>
<h2 id="h21"></h2>


这个翻译不正确。它会完全销毁并重新创建当前元素,因此会破坏任何已在其上注册的事件处理程序等内容。如果只想替换当前元素内部的内容(例如使用“=”),应该使用其他方法。 - Fraser
“这仅替换当前元素内被引用的内容(如使用“=”)。”- 唯一未复制的部分 - 事实上是不正确的 - 它不仅仅替换内容。它也销毁容器。我会根据我的看法投票 - 请随意“报告”你认为需要的任何内容。 - Fraser
@Fraser不是的,它并不会? outerHTML 目标是自己,因此在被替换时也会破坏/替换容器(自身)。innerHTML 替换所有子级,但不会破坏容器(自身)。如果您为使用 innerHTML 的元素添加了事件处理程序,则该事件处理程序将不会被破坏。它仍然能够正常工作,因为元素仍然存在。 - ravo10
修改 innerHTML 会导致内容重新解析和 DOM 节点被重新创建,从而丢失你所附加的任何处理程序。 - Fraser
@Fraser 是的!但你并没有谈论内容!你在提到的是容器。当一个元素被替换/销毁时,它当然包括被重新解析和DOM节点!我没有说过其他的事情。 - ravo10

4
我认为两者都不是您想要的,使用textContent或任何处理元素文本的属性。
elem.textContent = "This is the comment";
elem.classList.add("comment"); 

innerHTML将内容解析为HTML并完全破坏该元素并重新创建它,还会破坏可能已注册该元素的任何事件处理程序等。使用outerHTML,元素集仍将保留对原始元素(如果有)的引用。

因此,与设置文本内容的正确属性相比,两者都可能产生意外的副作用。


1
谢谢,这个答案在问题的语境下更有意义。 - spacing
@BKSpurgeon 不太确定你的问题是什么...如果你只想更新元素ID,那么你可以直接使用 foo.id = 1,不需要使用 innerHtml。此外,情况恰恰相反 - innerHtml 将删除与元素相关联的任何处理程序,因为它会销毁并重新创建元素。outerHTML 不会这样做 - 但99.99%的情况下,除非有非常好的理由,否则你都不应该使用它们。 - Fraser
1
@Fraser - 感谢您的回复。我的理解是,替换元素上的innerHTML将保留与特定元素相关联的任何事件处理程序,而仅更改其内容。但是您似乎在说这是不正确的? - BenKoshy
1
@BKSpurgeon - 是的,它会破坏元素,因此可能已在元素属性上设置的任何处理程序或其他数据也会被破坏。唯一的例外是保留的属性。请参见:https://dev59.com/0m435IYBdhLWcg3w9FHi - Fraser
@Fraser 很好!我之前的表述不够清晰。谢谢你详细的解释。处理程序被保留在父元素上,但会在所有子元素上被销毁:https://gist.github.com/benkoshy/01cf4310929b9fa822263bcc97ee6817 - BenKoshy
显示剩余2条评论

0
根据OP的问题、评论和一个好的答案,在这种情况下,最好使用elem.outerHTML,因为你可以在Rails中预解析输入。
如果你将决策转移到JavaScript端,良好的编码实践会建议手动创建所有节点。如果你正在处理数百个元素插入,那么你会注意到速度上的差异(如果你对两种解决方案进行基准测试)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接