2012-02-14 46 views
39

我知道adding innerHTML to document fragments最近已经讨论过了,并且希望能够看到DOM标准中的内容。但是,在此期间您应该使用哪种解决方法?将任意HTML插入到DocumentFragment中

也就是说,采取

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

我想无论是divspanfrag内,有一个简单的一行代码。

没有循环的加分。 jQuery是允许的,但我已经试过$(html).appendTo(frag);之后frag仍为空。

+0

如何:frag = html :) – 2012-02-14 21:03:05

回答

58

这里是modern browsers的方式,而不循环:

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

更新: 我发现用皮特的主要思想,这增加了IE11进来一个简单的方法:

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

覆盖率比<template>方法IE11,章好,测试OK ,FF。

现场测试/演示提供http://pagedemos.com/str2fragment/

+4

根本不支持IE,所以“现代浏览器”有点误导。 – 2015-02-24 21:00:50

+1

Upvoted因为它适用于所有4个现代浏览器。 – 2015-05-19 19:53:41

+0

如果在演示中不是''标签,则几乎可以投票。 – 2015-08-11 20:13:02

0

要做到这一点尽可能少线,你可以将你的内容包裹在另一个div,所以你不必循环或调用appendchild不止一次。使用jQuery(正如你所提到的那样)你可以很快地创建一个未连接的dom节点并将其放入片段中。

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

@RobW。这不是一个很好的理由,如果OP写道_“允许jQuery”_ – gdoron 2012-02-14 22:30:17

+0

@gdoron拒绝投票的理由我低估了答案的主要原因是文本解释是100%错误。一个“DocumentFragment”对象可以有任意数量的子元素。我之前的评论是指摩根对米歇尔的回答的评论。 – 2012-02-14 22:37:13

+0

@RobW这只是一个俏皮的评论,因为我们在同一时间发布。我可以看到其他人会如何看待它,尽管如此。我已将其删除。我也明白你的意思。在我的测试中,我犯了一个错误,并根据我的解释。我已经更新了我的答案。谢谢 – MorganTiley 2012-02-15 12:32:42

2

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

+0

是的,我不想要额外的容器元素。 – Domenic 2012-02-15 17:10:20

+0

当你追加你总是需要一个“额外”(或者我应该说一个目标)容器 - 是一个身体或其他标签。如果你不希望它是你的循环 – Michal 2012-02-15 18:51:00

+0

我想我一直希望有一种方法可以一次性将所有持有人的孩子复制到'frag'中(没有循环)。 'appendChildren'什么的。但这听起来像没有这样的方法存在。 – Domenic 2012-02-15 19:11:31

23

当前,仅使用字符串填充文档片段的唯一方法是创建一个临时对象,并循环通过子对象以追加他们到了片段。

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

如果要创建整个文档,请改为使用DOMParser。看看this answer

代码:

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

Bleh,我想这是唯一的出路。至少你真的回答了这个问题,并且满足了问题陈述:)。不过,不得不循环,这很烦人。呃,好吧。 – Domenic 2012-02-15 17:13:08

+0

错过了元素之间的文本.... 'var elemQueried = document.createDocumentFragment(); var tmp = document.createElement('body'),child; tmp.innerHTML ='

x
Bleh y'; var children = tmp.childNodes; while(children.length){elemQueried.appendChild(children [0]); }' – PAEz 2015-06-16 16:27:34

+0

@PAEz在下面发布了一个解决此问题的答案。 – Matt 2016-05-16 17:57:19

8

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

5

@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块吃亏,但是,它与许多旧的浏览器兼容,和简洁。

+2

甚至conciser:'.firstChild' --' while(intermediateContainer.firstChild)fragement.appendChild(intermediateContainer.firstChild);' – 2016-05-16 18:00:24

+0

好的建议。我想这是一个风格问题。谢谢! – Matt 2016-05-16 18:51:10

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

这不起作用(至少在Chrome中)。在DocumentFragment中使用insertAdjacentHTML时,会出现以下错误:未捕获的DOMException:未能在'Element'上执行'insertAdjacentHTML':该元素没有parent.'此外,addChild不是一种方法,您应该使用'appendChild' – KevBot 2017-02-28 02:13:26

0

就像@dandavis说的那样,使用模板标签有一个标准的方法。
但是,如果你想支持IE11,你需要解析像“< TD>考”表元素,您可以使用此功能:

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

这里是一个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; 
     } 
    }