17

谁能简要解释一下 documentFragment 的实际作用?我一直在寻找一个明确的解释,但直到现在我才得到任何解释。

我读到的是,documentFragment 类似于 DOM 结构,我们可以在其中添加修改 DOM 元素而不会中断文档的实际流程。

我还读到,documentFragment 比将每个元素一个一个地附加到 DOM 中要快。在我看来,documentFragment 不会每次都重新计算样式,所以它更快。

我有两个例子,

以片段方式进行:

var frag = document.createDocumentFragment();
var div1 = document.createElement("div");
var div2 = document.createElement("div");
frag.appendChild(div1);
frag.appendChild(div2);
document.getElementById("someId").appendChild(frag);

以正常方式进行:

var div = document.createElement("div");
var div1 = document.createElement("div");
var div2 = document.createElement("div");
div.appendChild(div1);
div.appendChild(div2);

document.getElementById("someId").appendChild(div);

上面两个例子中到底发生了什么?

4

2 回答 2

27

“片段方式”和“正常方式”之间有一个重要区别:

使用document.createElement

const div = document.createElement('div');
div.appendChild(document.createTextNode('Hello'));
div.appendChild(document.createElement('span'));
document.body.appendChild(div);
console.log(div.childNodes); // logs a NodeList [#text 'Hello', <span>]

这导致以下 DOM 结构:

<body>
  <div>
    Hello
    <span></span>
  </div>
</body>

使用DocumentFragment

const frag = document.createDocumentFragment();
frag.appendChild(document.createTextNode('Hello'));
frag.appendChild(document.createElement('span'));
document.body.appendChild(frag);
console.log(frag.childNodes); // logs an empty NodeList

这导致以下 DOM 结构:

<body>
  Hello
  <span></span>
</body>

这意味着调用appendChildinsertBefore使用实例DocumentFragment将文档片段的子节点移动到新的父节点。之后,文档片段为空。

正如您正确提到的那样,创建文档片段并向其附加多个元素比将这些元素一个一个地附加到真实的 DOM 更有效,这会导致浏览器每次重新渲染页面的某些部分。由于文档片段的内容在屏幕上不可见,因此该页面只需重新渲染一次。

每当您创建大型 DOM 结构时,建议您在文档片段中创建它,并在完成后将其附加到 DOM 中。

于 2017-08-07T07:26:58.340 回答
1

对于仅附加 2 个孩子,您不会看到任何性能问题。假设您有一个包含 100 个项目的书籍数组,并且您希望将它们附加到 DOM。您将编写以下代码:

let books=[,,,,,,,,,,,,,,,,]
let bookList;
document.addEventListener('DOMContentLoaded',load)
 function load(){
    bookList=document.getElementById('books')
    books.forEach(book=>{
        let li=document.createElement('li')
        li.textContext=book
        li.class="bookItem"
        // here is the headache part
        bookList.appendChild(li)     
    }))
   }

所以你要循环 100 次,每次,你要告诉浏览器重绘屏幕。这将占用大量资源。根据您使用的系统,您可能会看到屏幕闪烁。

用片段我会这样写load

function load(){
     bookList=document.getElementById('books')
     let df=new DocumentFragment()
     books.forEach(book=>{
         let li=document.createElement('li')
         li.textContext=book
         li.class="bookItem"
         // we are appending to df not to the bookList
         df.appendChild(li)     
    })
    // I collected all list elements inside DocumentFragment
    // Now I append it to the bookList
    bookList.appendChild(df)
  }

创建document fragment就像创建一个div. 但它不会向页面添加任何 Html。您不会在 HTML 源代码中看到:

 <DocumentFragment></DocumentFragment>

它只是一个空容器,用于容纳 Html 的其他部分。片段可以在单个操作中注入和克隆,而不必一遍又一遍地注入和克隆每个单独的节点。我们正在以更好的性能实现完全相同的目标。

于 2022-01-24T23:12:56.750 回答