javascript-将任意HTML插入DocumentFragmen

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

也就是说,拿

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

我想要2701071326567203843842和2701071326567203843841都位于frag内,且衬里很容易。

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

Domenic asked 2020-01-13T16:48:35Z
10个解决方案
85 votes

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

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

覆盖范围比2710071698752963584方法要好,并且在IE11,Ch,FF中进行了测试。

可以进行实时测试/演示[http://pagedemos.com/str2fragment/]

dandavis answered 2020-01-13T16:49:01Z
24 votes

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

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

如果要创建整个文档,请改用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);
Rob W answered 2020-01-13T16:49:43Z
12 votes

使用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中的自定义元素将立即随范围升级,但仅当使用模板将其克隆到实际文档中时才可以。 模板方法更具“惰性”,这可能是合乎需要的。

Pete Blois answered 2020-01-13T16:50:17Z
5 votes

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

Matt answered 2020-01-13T16:50:42Z
2 votes

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对象。 一旦准备好将其追加,只需将其追加到页面上的现有元素

Michal answered 2020-01-13T16:51:07Z
2 votes

就像@dandavis所说的那样,有一种使用template-tag的标准方法。
但是,如果您想支持IE11,并且需要解析“ <td> 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;
}
Tobias Buschor answered 2020-01-13T16:51:32Z
1 votes

这是一个x浏览器解决方案,已在IE10,IE11,Edge,Chrome和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;
        }
    }
bnieland answered 2020-01-13T16:51:57Z
0 votes

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

var html = '<div id="main"><div>x</div><span>y</span></div>';
var frag = document.createDocumentFragment();
frag.appendChild($​(html)[0]);
Morgan T. answered 2020-01-13T16:52:17Z
0 votes
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);
Guest answered 2020-01-13T16:52:34Z
0 votes

没有人提供过所要求的“简单一线”。

给定变量...

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);
Patrick Dark answered 2020-01-13T16:53:03Z
translate from https://stackoverflow.com:/questions/9284117/inserting-arbitrary-html-into-a-documentfragment