我应该使用document.createDocumentFragment还是document.createElement

scr*_*key 89 javascript dom

我正在阅读有关文档片段和DOM重排的内容,并想知道它们看起来有多么document.createDocumentFragment不同,document.createElement因为在将它们附加到DOM元素之前,它们都不存在于DOM中.

我做了一个测试(下面),他们都花了相同的时间(大约95ms).猜测这可能是由于没有任何样式应用于任何元素,因此可能没有回流.

无论如何,基于下面的例子,我为什么要使用createDocumentFragment而不是createElement在插入DOM时使用两者之间的差异.

var htmz = "<ul>";
for (var i = 0; i < 2001; i++) {
    htmz += '<li><a href="#">link ' + i + '</a></li>';
}
htmz += '<ul>';

//createDocumentFragment
console.time('first');
var div = document.createElement("div");
div.innerHTML = htmz;
var fragment = document.createDocumentFragment();
while (div.firstChild) {
    fragment.appendChild(div.firstChild);
}
$('#first').append(fragment);
console.timeEnd('first');

//createElement
console.time('second');
var span = document.createElement("span");
span.innerHTML = htmz;
$('#second').append(span);
console.timeEnd('second');


//jQuery
console.time('third');
$('#third').append(htmz);
console.timeEnd('third');
Run Code Online (Sandbox Code Playgroud)

Tim*_*own 92

不同之处在于,将文档片段添加到DOM时,文档片段会有效消失.会发生的是文档片段的所有子节点都插入到DOM中插入文档片段的位置,并且未插入文档片段本身.片段本身仍然存在,但现在没有孩子.

这允许您同时将多个节点插入DOM:

var frag = document.createDocumentFragment();
var textNode = frag.appendChild(document.createTextNode("Some text"));
var br = frag.appendChild(document.createElement("br"));
var body = document.body;
body.appendChild(frag);
alert(body.lastChild.tagName); // "BR"
alert(body.lastChild.previousSibling.data); // "Some text"
alert(frag.hasChildNodes()); // false
Run Code Online (Sandbox Code Playgroud)

  • 是的,这绝对是使用它的一个原因.此外,文档片段可以包含任何类型的节点,而元素可以不包含. (4认同)
  • 谢谢你的回复.你说它允许同时进行多次插入,但我可以使用doc.createElement实现.唯一的区别是我必须首先将元素包装在<span>标记中,然后将<span>插入到DOM中.这就是为什么我应该使用createDocumentFragment?为了避免将不必要的元素插入DOM中? (3认同)
  • 实际上片段并没有"消失"; 浏览器将其childNodes移动到DOM.因此片段仍然存在,但插入后它将为空. (3认同)
  • @inf3rno:因此,我使用了“有效地”一词以及随后的解释,这与您的解释大致相同。我承认我应该在答案中明确指出片段继续存在,没有子节点。 (2认同)

Jer*_*her 7

创建元素和文档片段之间的另一个非常重要的区别:

当您创建元素并将其附加到DOM时,该元素将附加到DOM以及子元素.

使用文档片段,仅附加子项.

以下为例:

var ul = document.getElementById("ul_test");


// First. add a document fragment:


(function() {
  var frag = document.createDocumentFragment();
  
  
  var li = document.createElement("li");
  li.appendChild(document.createTextNode("Document Fragment"));
  frag.appendChild(li);
  
  ul.appendChild(frag);
  console.log(2);
}());

(function() {
  var div = document.createElement("div");
  
  
  var li = document.createElement("li");
  li.appendChild(document.createTextNode("Inside Div"));
   div.appendChild(li);
  
  ul.appendChild(div);
}());
Run Code Online (Sandbox Code Playgroud)
Sample List:
<ul id="ul_test"></ul>
Run Code Online (Sandbox Code Playgroud)

导致这种格式错误的HTML(添加了空格)

<ul id="ul_test">
  <li>Document Fragment</li>
  <div><li>Inside Div</li></div>
</ul>
Run Code Online (Sandbox Code Playgroud)


Cha*_*wen 5

您可以将 DocumentFragment 视为虚拟 DOM。它没有连接到 DOM,并且与元素不同,它没有父元素。然后,您可以与该片段进行交互,就好像它是一个虚拟文档对象一样。一切都在记忆中。

当您需要进行许多 DOM 操作或样式更改时,使用片段确实很有帮助,因为这些操作会触发回流和重绘 - DOM 上的昂贵操作会减慢页面加载速度。

使用fragment 获得的好处是,当fragment 插入到DOM 中时,无论它包含多少个子级,它都只会触发一次回流。

DocumentFragment 不是元素或节点。它是一个精简的 Document 对象,具有减少的属性和方法集。

如果您听说过 React 的虚拟 DOM,那么他们会大量使用 ReactDOM 库中的 DocumentFragments。这就是它如此高效的原因。