2012-02-14 44 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; 
     } 
    }