documentFragment深入理解

1,968 阅读2分钟

先搬一段官方的描述:

DocumentFragment 表示一个没有父级文件的最小文档对象。它被当做一个轻量版的 Document 使用,用于存储已排好版的或尚未打理好格式的XML片段。最大的区别是因为DocumentFragment不是真实DOM树的一部分,它的变化不会引起DOM树的重新渲染的操作(reflow) ,且不会导致性能等问题。

DocumentFragment 接口表示文档的一部分(或一段)。更确切地说,它表示一个或多个邻接的 Document 节点和它们的所有子孙节点。 DocumentFragment 节点不属于文档树,继承的 parentNode 属性总是 null。 不过它有一种特殊的行为,该行为使得它非常有用,即当请求把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。 这使得 DocumentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作,尤其是与 Range 接口一起使用时更是如此。 可以用 Document.createDocumentFragment() 方法创建新的空 DocumentFragment 节点


这样我们就明白了documentFragment的一些特性,它被修改的之后不会去渲染浏览器页面,不会引起浏览器的重绘与回流,我们可以把它作为一个中转站,把多次的dom操作汇聚到这一次来进行,把需要添加的dom元素都先添加到documentFragment中去,减少回流次数,就可以实现性能的优化了。


基本用法:

//初始显示test1
<div id="test">
        <li>test1</li>
        <li>test1</li>
        <li>test1</li>
    </div>
const ul = document.getElementById('test')
// 创建fragment对象
const fragment = document.createDocumentFragment()
console.log(fragment.nodeValue); //null
console.log(fragment.nodeName); //#document-fragment
console.log(fragment.nodeType); //
//  取出ul中的所有子节点并保存到fragment
let child;
while(child=ul.firstChild) {
  fragment.appendChild(child)
}
//更新fragment中的所有节点(li的内容)
Array.prototype.slice.call(fragment.childNodes).forEach(node => {
  if (node.nodeType===1) {//取得元素节点
    node.textContent = 'test2' //重新赋值为test2
  }
})
// 将fragment插入到ul
ul.appendChild(fragment)

所以使用documentFragment来进行批量跟新的操作可以极大的节省性能。