DOMParser 与模板和 innerHTML 的优势

Posted

技术标签:

【中文标题】DOMParser 与模板和 innerHTML 的优势【英文标题】:Advantages to DOMParser vs template & innerHTML 【发布时间】:2016-09-11 23:06:15 【问题描述】:

我正在寻找处理解析 html 或 XHTML(XML 序列化)标记并将其插入网页的 DOM 的最佳方法,该网页可以是 text/html 或 application/xhtml+xml。不打算使用像 jQuery 这样的库,只关心与最新版本的 Chrome 的兼容性。

我看到了两种可能的解决方案。

模板和内部HTML:

let temp = document.createElement('template');
temp.innerHTML = markuptext;
document.body.appendChild(temp.content);

DOMParser:

let parser = new DOMParser();
let doc = parser.parseFromString('<div xmlns="http://www.w3.org/1999/xhtml">' + markuptext + '</div>', 'application/xhtml+xml');
let frag = document.createDocumentFragment(), childNode;
while (childNode = doc.documentElement.firstChild) 
    frag.appendChild(childNode);

document.body.appendChild(frag);

我希望有人能指出这两种方法的优缺点。

使用 Template & innerHTML 我假设 Chrome 会根据页面的内容类型选择解析为 HTML/XML,并且可能无法更改它。似乎 Template & innerHTML 允许像 &lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt; 这样的片段在 &lt;tbody&gt; 之外,无论它是解析为 HTML 还是 XML。 DOMParser 也允许这样做,但如果它被解析为 XML。

【问题讨论】:

DHTML 属性 innerHTML 是一个成熟的 HTML 解析器,在将 HTML 流序列立即转换为 DOM 树时高度优化且同样可靠(在所有浏览器引擎)。作为奖励,它还可以对不完整的流进行错误更正。 @BekimBacaj "it may also be able to make error corrections on an incomplete stream" 如果属实,我会认为这是负面的。 我认为这是一个好处——因为存在任何类型的数据结构语言的唯一原因是实际数据。这就是你感兴趣的全部,你根本不在乎它的结构,只要你得到你正在寻找或等待的信息。无论如何,除此之外的任何行为都注定会像 xhtml 一样过早死亡。 @BekimBacaj 我完全不同意。我希望我的标记格式正确,如果不是,我希望它告诉我,而不是默默地尝试猜测它的实际含义。这些不是标记错误的借口。但我离题了。 见***.com/questions/37554623/… - DOMParser 更安全 【参考方案1】:

这取决于你的目标是什么。如果您只想“按原样”附加已解析的 html/xhtml,则使用 .innerHTML,它更容易且通常更快。 但是,根据我的经验,通常,您必须进行某种转换,然后使用 dom 操作是最好的方法。但是您应该避免在循环中逐个节点附加到 document.body,因为它速度慢且效率低,只需创建一些“虚拟” dom 元素,在循环中添加节点,而不是附加整个对象:

let div = document.createElement('div');
let childNode;
while (childNode = doc.documentElement.firstChild) 
    div.appendChild(childNode);

document.body.appendChild(div);

一个重要的注意事项,关于尝试在 JS 中找到最有效的解决方案。 JS 性能高度依赖于 javascript 引擎,未来会优化 js 的哪些部分。因此,您应该始终编写某种性能测试(或使用准备好的测试套件),尤其是关于 DOM API 之类的缓慢“部分”。好消息是,引擎开发人员倾向于支持众所周知的解决方案和“良好实践”进行优化,他们通常会留下“不好的部分”。

以下是关于 innerHTML 与 DOM 附加的一些很好的测试: http://andrew.hedges.name/experiments/innerhtml/

在不创建“虚拟”div 的情况下附加到 DOm: https://coderwall.com/p/o9ws2g/why-you-should-always-append-dom-elements-using-documentfragments

以及更多关于 .innerHTML、.appendChild、.insertAdjacentHTML 的技术说明" "innerHTML += ..." vs "appendChild(txtNode)"

【讨论】:

我使用DocumentFragment 更新了我的 DOMParser 代码,以避免多次附加到 document.body。【参考方案2】:

也许是一种混合方法?

var dom = new DOMParser().parseFromString('<template>'+ markuptext +'</template>','text/html').head;
document.getElementById('my-div').appendChild(dom.firstElementChild.content);

【讨论】:

【参考方案3】:

在此页面上,他们建议第一个解决方案是:

let tmpl = document.createElement('template');
tmpl.innerHTML = text;
shadowRoot.appendChild(tmpl.content.cloneNode(true));

https://developers.google.com/web/fundamentals/web-components/customelements

【讨论】:

以上是关于DOMParser 与模板和 innerHTML 的优势的主要内容,如果未能解决你的问题,请参考以下文章

innerHtml +花括号的角度5问题

innerHtml 未正确绘制 ngFor 模板

使用 html <模板>:innerHTML.replace

将模板添加为 innerHTML 时,Angular 2 绑定/事件不起作用

JavaScript RND - innerHTML的简单模板

在 JavaScript 中不使用 DOMParser 的 XML 解析