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 允许像 <tr><td></td></tr>
这样的片段在 <tbody>
之外,无论它是解析为 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 的优势的主要内容,如果未能解决你的问题,请参考以下文章
使用 html <模板>:innerHTML.replace
将模板添加为 innerHTML 时,Angular 2 绑定/事件不起作用