0
点赞
收藏
分享

微信扫一扫

虚拟滚动列表的设计

jjt二向箔 2022-02-23 阅读 191
htmlcss

虚拟滚动列表的设计

因为 DOM 元素的创建和渲染需要的时间成本很高,在大数据的情况下,完整渲染列表所需要的时间不可接收。其中一个解决思路就是在任何情况下只对「可见区域」进行渲染,可以达到极高的初次渲染性能。

虚拟列表中有两个重要概念

  • 可视区域
  • 可滚动区域:当列表中的数据总量 * 每一项的高度大于可视区域时,那么就只会展示可视区域中的数据,其他数据通过滚动进行展示。

实现虚拟列表就是处理滚动条滚动后的可见区域的变更,其中具体步骤如下:

  1. 计算当前可见区域起始数据的 startIndex
  2. 计算当前可见区域结束数据的 endIndex
  3. 计算当前可见区域的数据,并渲染到页面中
  4. 计算 startIndex 对应的数据在整个列表中的偏移位置 startOffset,并设置到列表上

请添加图片描述

可视区域布局

  • 最外层元素(.wrapper)使用相对定位
  • 使用一个元素(.list-view)撑起这个列表,让列表的滚动条出现
  • 列表的可见元素(.list-view-content)使用绝对定位,left、right、top 设置为 0
<div class="wrapper">
  <div class="list-view">
    <div class="list-view-content">
      <div class="header ">header</div>
      <div class="content ">content</div>
      <div class="sidebar ">sidebar</div>
      <div class="footer ">footer</div>
  </div>
</div>
.wrapper{
height:100%;
overflow:auto;
position:relative;
}
.list-view{
  height: 100px;
}
.list-view-content{
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}
.header {
  height: 50px;
  background: saddlebrown;
}
.sidebar{
  height: 50px;
  background: red;
}
.content{
  height: 50px;
  background: violet;
}
.footer{
  height: 50px;
  background: yellow;
}

请添加图片描述

在这个例子中,.list-view这个元素的高度就是可视区域的高度,当.list-view-content中的所有项的高度总和大于可视区域的高度时,就会出现下拉框。

那么,现在的问题就是如何在可视区域中加载对应项的元素了。

计算.list-view的滚动高度(scrollTop),除去每一项的高度,就是要可视区域中的要第一个要展示的项的索引。

const shouldStartIndex = Math.floor(scrollTop / nodeHeight);

但是由于索引是从开始算的,所以我们展示的真实节点的索引应该是要减去1的。

const realStartIndex = shouStartIndex - 1;

计算可视区域的最后一项的索引,就是滚动高度(scrollTop) + 可视高度(clientHeight) 除于每一项的高度

const shouldEndIndex = Math.ceil((scrollTop + clientHeight) / nodeHeight);

由于有可能已经展示到最后一个了,所以可视区域中最后一个元素要判断一下,因为最后是用slice的方式截取,所以需要加1

const realEndIndex = Math.min(array.length, shouldEndIndex + 1);

最后面就是为可视区域加一个transform的动画了

clientElement.style.transform = `translateY(${realStartIndex * nodeHeight}px)`;

之后就是slice截取到对应的数据,重新渲染就可以了。

写在最后

由于elementUItree组件没有采用虚拟列表的方式,在渲染大数据量时会生成大量的DOM,因此我使用虚拟滚动树结合ElementUItree组件的设计思想实现了和 element-ui API 基本一致的能够应对较大数据量的树组件。

可以通过命令安装后使用

npm i vvtree --save-dev

也可查看源代码:
https://github.com/leopord-lau/VTree

举报

相关推荐

0 条评论