将任意 HTML 插入 DocumentFragment

发布于 2025-01-05 19:12:55 字数 496 浏览 2 评论 0原文

我知道最近innerHTML 添加到文档片段讨论过,并有望包含在 DOM 标准中。但是,您同时应该使用什么解决方法?

也就是说,

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

我想要 frag 内部的 divspan,并使用简单的一行代码。

无循环的奖励积分。允许使用 jQuery,但我已经尝试过 $(html).appendTo(frag);之后 frag 仍然是空的。

I know that adding innerHTML to document fragments has been recently discussed, and will hopefully see inclusion in the DOM Standard. But, what is the workaround you're supposed to use in the meantime?

That is, take

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

I want both the div and the span inside of frag, with an easy one-liner.

Bonus points for no loops. jQuery is allowed, but I've already tried $(html).appendTo(frag); frag is still empty afterward.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

冷月断魂刀 2025-01-12 19:12:55

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

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);
}

覆盖范围比

提供实时测试/演示http://pagedemos.com/str2fragment/

Here is a way in modern browsers without looping:

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

var frag = temp.content;

or, as a re-usable

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

UPDATE:
I found a simpler way to use Pete's main idea, which adds IE11 to the mix:

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

The coverage is better than the <template> method and tested ok in IE11, Ch, FF.

Live test/demo available http://pagedemos.com/str2fragment/

冰之心 2025-01-12 19:12:55

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

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

如果您想创建整个文档,请使用 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);

Currently, the only way to fill a document fragment using only a string is to create a temporary object, and loop through the children to append them to the fragment.

  • Since it's not appended to the document, nothing is rendered, so there's no performance hit.
  • You see a loop, but it's only looping through the first childs. Most documents have only a few semi-root elements, so that's not a big deal either.

If you want to create a whole document, use the DOMParser instead. Have a look at this answer.

Code:

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

A one-liner (two lines for readability) (input: String html, output: DocumentFragment frag):

var frag =document.createDocumentFragment(), t=document.createElement('body'), c;
t.innerHTML = html; while(c=t.firstElementChild) frag.appendChild(c);
请你别敷衍 2025-01-12 19:12:55

使用 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);

请注意,此方法与 < code>

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

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

Use 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);

Note that the primary differences between this approach and the <template> approach are:

  • Range.createContextualFragment is a bit more widely supported (IE11 just got it, Safari, Chrome and FF have had it for a while).

  • Custom elements within the HTML will be upgraded immediately with the range, but only when cloned into the real doc with template. The template approach is a bit more 'inert', which may be desirable.

瑾夏年华 2025-01-12 19:12:55

没有人提供所要求的“简单的一句话”。

给定变量…………

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);

No one ever provided the requested "easy one-liner".

Given the variables…

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

… the following line will do the trick (in Firefox 67.0.4):

frag.append(...new DOMParser().parseFromString(html, "text/html").body.childNodes);
云淡风轻 2025-01-12 19:12:55

@PAEz 指出@RobW 的方法不包括元素之间的文本。这是因为 children 只获取元素,而不是节点。更可靠的方法可能如下:

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 块上性能可能会受到影响,但是它与许多旧版浏览器兼容并且简洁。

@PAEz pointed out that @RobW's approach does not include text between elements. That's because children only grabs Elements, and not Nodes. A more robust approach might be as follows:

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]);
}

Performance may suffer on larger chunks of HTML, however, it is compatible with many older browsers, and concise.

九八野马 2025-01-12 19:12:55

createDocumentFragment 创建一个空的 DOM“容器”。 innerHtml 和其他方法仅适用于 DOM 节点(而不是容器),因此您必须首先创建节点,然后将它们添加到片段中。您可以使用一种痛苦的appendChild 方法来完成此操作,也可以创建一个节点并修改它的innerHtml 并将其添加到您的片段中。

var frag = document.createDocumentFragment();
    var html = '<div>x</div><span>y</span>';
var holder = document.createElement("div")
holder.innerHTML = html
frag.appendChild(holder)

使用 jquery,您只需将 html 保留并构建为字符串即可。如果你想将它转换为 jquery 对象以对其执行类似 jquery 的操作,只需执行 $(html) 即可在内存中创建一个 jquery 对象。准备好附加它后,您只需将其附加到页面上的现有元素即可

createDocumentFragment creates an empty DOM "container". innerHtml and other methods work only on DOM nodes (not the container) so you have to create your nodes first and then add them to the fragment. You can do it using a painful method of appendChild or you can create one node and modify it's innerHtml and add it to your fragment.

var frag = document.createDocumentFragment();
    var html = '<div>x</div><span>y</span>';
var holder = document.createElement("div")
holder.innerHTML = html
frag.appendChild(holder)

with jquery you simply keep and build your html as a string. If you want to convert it to a jquery object to perform jquery like operations on it simply do $(html) which creates a jquery object in memory. Once you are ready to append it you simply append it to an existing element on a page

乖不如嘢 2025-01-12 19:12:55

就像 @dandavis 所说,有一个使用模板标签的标准方法。
但是如果你想支持IE11并且需要解析像'test'这样的表格元素,你可以使用这个函数:

function createFragment(html){
    var tmpl = document.createElement('template');
    tmpl.innerHTML = html;
    if (tmpl.content == void 0){ // ie11
        var fragment = document.createDocumentFragment();
        var isTableEl = /^[^\S]*?<(t(?:head|body|foot|r|d|h))/i.test(html);
        tmpl.innerHTML = isTableEl ? '<table>'+html : html;
        var els        = isTableEl ? tmpl.querySelector(RegExp.$1).parentNode.childNodes : tmpl.childNodes;
        while(els[0]) fragment.appendChild(els[0]);
        return fragment;
    }
    return tmpl.content;
}

Like @dandavis said, there is a standard way by using the template-tag.
But if you like to support IE11 and you need to parse table elements like '<td>test', you can use this function:

function createFragment(html){
    var tmpl = document.createElement('template');
    tmpl.innerHTML = html;
    if (tmpl.content == void 0){ // ie11
        var fragment = document.createDocumentFragment();
        var isTableEl = /^[^\S]*?<(t(?:head|body|foot|r|d|h))/i.test(html);
        tmpl.innerHTML = isTableEl ? '<table>'+html : html;
        var els        = isTableEl ? tmpl.querySelector(RegExp.$1).parentNode.childNodes : tmpl.childNodes;
        while(els[0]) fragment.appendChild(els[0]);
        return fragment;
    }
    return tmpl.content;
}
美男兮 2025-01-12 19:12:55

我会选择这样的东西..

function fragmentFromString(html) {
  const range = new Range();
  const template = range.createContextualFragment(html);
  range.selectNode(template.firstElementChild);
  return range;
}

// Append to body
// document.body.append(fragmentFromString(`<div>a</div>`).cloneContents())

通过这种方式,您可以将内容保存在 Range 对象内,并且可以免费获得所有需要的方法。

您可以在此处找到所有 Range 方法和属性的列表 https:// developer.mozilla.org/en-US/docs/Web/API/Range

注意:完成后记得使用 detatch() 方法以避免泄漏并提高性能。

I would go with something like this..

function fragmentFromString(html) {
  const range = new Range();
  const template = range.createContextualFragment(html);
  range.selectNode(template.firstElementChild);
  return range;
}

// Append to body
// document.body.append(fragmentFromString(`<div>a</div>`).cloneContents())

This way you keep the content inside a Range object and you get all the needed methods for free.

You can find the list of all Range methods and properties here https://developer.mozilla.org/en-US/docs/Web/API/Range

Note: Remember to use detatch() method once you are done with it to avoid leaks and improve performance.

挽清梦 2025-01-12 19:12:55

这是一个 x 浏览器解决方案,在 IE10、IE11、Edge、Chrome 和 FF 上进行了测试。

 function HTML2DocumentFragment(markup: string) {
        if (markup.toLowerCase().trim().indexOf('


Here is a x-browser solution, tested on IE10, IE11, Edge, Chrome and FF.

    function HTML2DocumentFragment(markup: string) {
        if (markup.toLowerCase().trim().indexOf('<!doctype') === 0) {
            let doc = document.implementation.createHTMLDocument("");
            doc.documentElement.innerHTML = markup;
            return doc;
        } else if ('content' in document.createElement('template')) {
            // Template tag exists!
            let el = document.createElement('template');
            el.innerHTML = markup;
            return el.content;
        } else {
            // Template tag doesn't exist!
            var docfrag = document.createDocumentFragment();
            let el = document.createElement('body');
            el.innerHTML = markup;
            for (let i = 0; 0 < el.childNodes.length;) {
                docfrag.appendChild(el.childNodes[i]);
            }
            return docfrag;
        }
    }
看透却不说透 2025-01-12 19:12:55
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
var e = document.createElement('i');
frag.appendChild(e);
e.insertAdjacentHTML('afterend', html);
frag.removeChild(e);
var html = '<div>x</div><span>y</span>';
var frag = document.createDocumentFragment();
var e = document.createElement('i');
frag.appendChild(e);
e.insertAdjacentHTML('afterend', html);
frag.removeChild(e);
平定天下 2025-01-12 19:12:55

要使用尽可能少的行来完成此操作,您可以将上面的内容包装在另一个 div 中,这样您就不必多次循环或调用appendchild。使用 jQuery(正如您所提到的,是允许的)您可以非常快速地创建一个独立的 dom 节点并将其放置在片段中。

var html = '<div id="main"><div>x</div><span>y</span></div>';
var frag = document.createDocumentFragment();
frag.appendChild($​(html)[0]);

To do this with as little lines as possible, you could wrap your content above in another div so you do not have to loop or call appendchild more than once. Using jQuery (as you mentioned is allowed) you can very quickly create an unattached dom node and place it in the fragment.

var html = '<div id="main"><div>x</div><span>y</span></div>';
var frag = document.createDocumentFragment();
frag.appendChild($​(html)[0]);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文