利用js在最大程度减少回流的情况下,对列表各项进行修改(createDocumentFragment的使用)

  最近遇到一个题目,大致如下:假设有一个Todo-List,共有1000项数据,假设里面有100条数据已经过期,需要在后面添加上"已过期"字样,如何实现,怎样才能最大程度的减少回流的发生?

  刚拿到题目的时候我就在想,这不是挺简单的吗,遍历一遍数据列表,在已过期的数据后面插入一个absolute的span标签不就完事了吗。然而事情并没有那么简单,面试官说,这只是局部减少了回流的发生,还有更好的解决方案。当时并没有想到更好的解决方案,回来之后查阅资料才知道,原来是可以使用createDocumentFragment来实现,用该方法可以更大程度的避免回流。

  首先我们先了解一下什么是documentFragment:

  documentFragment,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的 Document 使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。与document相比,最大的区别是DocumentFragment 不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。 最常用的方法是使用文档片段作为参数(例如,任何 Node 接口类似 Node.appendChild 和 Node.insertBefore 的方法),这种情况下被添加(append)或被插入(inserted)的是片段的所有子节点, 而非片段本身。因为所有的节点会被一次插入到文档中,而这个操作仅发生一个重渲染的操作,而不是每个节点分别被插入到文档中,因为后者会发生多次重渲染的操作。(摘自MDN,https://developer.mozilla.org/zh-CN/docs/Web/API/DocumentFragment)

  简单来说,通过createDocumentFragment()就可以创建出一个虚拟结点,它不属于DOM树的一部分,我们在上面所做的修改不会导致DOM的重新渲染,并且我们可以使用修改真实DOM结点的方法去修改documentFragment生成的结点。当我们准备将documentFragment插入DOM中时,插入的并不是documentFragment本身,而是将其所有子孙结点插入。所以当我们需要添加多个DOM结点或者修改多个DOM结点时,可以先将这些元素添加dDocumentFragment中,再统一将documentFragment添加到页面,这会大大减少页面渲染DOM的次数,效率会明显提升。(注意:如果使用appendChid方法将原dom树中的节点添加到DocumentFragment中时,会删除原来的节点)

  至此,比上述方法更优的解决方案就出来了:我们可以先遍历一遍原有的列表,若当前项未过期,则直接将其添加到我们新建的documentFragment结点中,若以过期,则在添加“已过期”字样之后再加入documentFragment,遍历完毕之后再将documentFragment挂载到原有的Todo-List中即可。

 

posted @ 2020-11-19 00:30  卑微小陈的随笔  阅读(160)  评论(0编辑  收藏  举报