将任意 HTML 插入 DocumentFragment

IT技术 javascript jquery documentfragment
2021-03-03 17:49:47

我知道最近讨论了添加innerHTML到文档片段的问题,并且希望将其包含在 DOM 标准中。但是,在此期间您应该使用的解决方法是什么?

也就是说,取

var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();

我想要 的divspan里面的frag,有一个简单的单衬。

没有循环的奖励积分。jQuery 是允许的,但我已经尝试过$(html).appendTo(frag)frag之后还是空的。

6个回答

这是现代浏览器中一种无需循环的方法:

var temp = document.createElement('template');
temp.innerHTML = '<div>x</div><span>y</span>';

var frag = temp.content;

或者,作为可重复使用的

function fragmentFromString(strHTML) {
    var temp = document.createElement('template');
    temp.innerHTML = strHTML;
    return temp.content;
}

更新:我找到了一种更简单的方法来使用 Pete 的主要思想,它将 IE11 添加到组合中:

function fragmentFromString(strHTML) {
    return document.createRange().createContextualFragment(strHTML);
}

覆盖率优于该<template>方法,在 IE11、Ch、FF 中测试正常。

现场测试/演示可用http://pagedemos.com/str2fragment/

我需要来自 Fragment 的元素节点数组,这适用于 Chrome 和 IE11 [].slice.call(temp.content ? temp.content.children : temp.childNodes)
2021-04-21 17:49:47
createContextualFragment 的一个问题是,像 '<td>test</td>' 这样的 html 会忽略 td(并且只创建 'test' 文本节点)。模板标签解决方案是要走的路。BTW Edge 13 现在支持模板标签。
2021-04-26 17:49:47
IE 根本不支持,所以“现代浏览器”有点误导。
2021-05-03 17:49:47
如果不是<font>演示中的那个标签,几乎被点赞了。
2021-05-06 17:49:47
你有什么好的 Safari 替代方案吗?或者至少是他们的跟踪器中的一个问题?
2021-05-14 17:49:47

目前,仅使用字符串填充文档片段的唯一方法是创建一个临时对象,并循环遍历子对象以将它们附加到片段中。

  • 由于它未附加到文档中,因此不会呈现任何内容,因此不会影响性能。
  • 你看到一个循环,但它只循环第一个孩子。大多数文档只有几个半根元素,所以这也没什么大不了的。

如果要创建整个文档,请改用 DOMParser。看看这个答案

代码:

var frag = document.createDocumentFragment(),
    tmp = document.createElement('body'), child;
tmp.innerHTML = '<div>x</div><span>y</span>';
while (child = tmp.firstElementChild) {
    frag.appendChild(child);
}

一行(两行可读)(输入:String html,输出:)DocumentFragment frag

var frag =document.createDocumentFragment(), t=document.createElement('body'), c;
t.innerHTML = html; while(c=t.firstElementChild) frag.appendChild(c);
@PAEz 在下面发布了一个解决这个问题的答案。
2021-04-23 17:49:47
缺少元素之间的文本.... var elemQueried = document.createDocumentFragment(); var tmp = document.createElement('body'), child; tmp.innerHTML = '<div>x</div>Bleh<span>y</span>'; var children = tmp.childNodes; while(children.length){ elemQueried.appendChild(children[0]); }
2021-05-05 17:49:47
Bleh,我想这是唯一的出路。至少您实际上回答了问题并满足了问题陈述:)。尽管如此,循环还是很烦人的;呃,好吧。
2021-05-20 17:49:47

使用Range.createContextualFragment

var html = '<div>x</div><span>y</span>';
var range = document.createRange();
// or whatever context the fragment is to be evaluated in.
var parseContext = document.body; 
range.selectNodeContents(parseContext);
var fragment = range.createContextualFragment(html);

请注意,此方法与<template>方法之间的主要区别是:

  • Range.createContextualFragment 得到了更广泛的支持(IE11 刚刚获得它,Safari、Chrome 和 FF 已经拥有它一段时间了)。

  • HTML 中的自定义元素将立即随范围升级,但只有在使用模板克隆到真实文档时才会升级。模板方法有点“惰性”,这可能是可取的。

小心!不规范。
2021-04-26 17:49:47
这应该是选定的答案,值得更多的赞成 <3
2021-05-09 17:49:47
它不适用于td,th元素table
2021-05-11 17:49:47

从来没有人提供过要求的“简单的单线”。

鉴于变量...

var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();

……下面这行代码可以解决问题(在 Firefox 67.0.4 中):

frag.append(...new DOMParser().parseFromString(html, "text/html").body.childNodes);
毫无疑问!这是最好的答案!旧版浏览器(包括 IE9)支持 documentFragments 和 DOMParser。竖起大拇指
2021-05-17 17:49:47

@PAEz 指出@RobW 的方法不包括元素之间的文本那是因为children只抓取Elements,而不抓取Nodes更稳健的方法可能如下:

var fragment = document.createDocumentFragment(),
    intermediateContainer = document.createElement('div');

intermediateContainer.innerHTML = "Wubba<div>Lubba</div>Dub<span>Dub</span>";

while (intermediateContainer.childNodes.length > 0) {
    fragment.appendChild(intermediateContainer.childNodes[0]);
}

性能可能会在较大的 HTML 块上受到影响,但是,它与许多旧浏览器兼容,并且简洁。

好建议。我想这是一个风格问题。谢谢!
2021-05-03 17:49:47
更简洁:.firstChild-while (intermediateContainer.firstChild) fragement.appendChild(intermediateContainer.firstChild);
2021-05-19 17:49:47