【问题标题】:how Document Fragment works?文档片段如何工作?
【发布时间】:2023-03-27 09:39:01
【问题描述】:

谁能简要解释一下 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);

上面两个例子中究竟发生了什么?

【问题讨论】:

标签: javascript html dom documentfragment


【解决方案1】:

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

使用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>

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

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

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

【讨论】:

  • 好吧,我明白你上面说的。但我有最后一个问题。在“正常方式”中,是否会发生多个渲染进程将“div”附加到“someId”?
  • 不,那样的话,大概只有一次渲染调用,不会有太大区别。 DocumentFragments 非常适合插入一系列元素。
  • 耶!太感谢了!现在有了明确的想法!! @PeterMader
【解决方案2】:

对于仅附加 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 的其他部分。可以在单个操作中注入和克隆片段,而不必注入和克隆每个片段 单个节点一遍又一遍。我们正在以更好的性能实现完全相同的目标。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多