1 什么是虚拟列表
虚拟列表其实是按需显示的一种实现,即只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染的技术,从而达到极高的渲染性能。
如上图所示,当采用虚拟列表来优化。就需要只渲染可视区域内的 item3 到 item10 这几个列表项。相比于渲染全部列表项,可以大大提高性能
2 虚拟列表优点
- 减少性能消耗
- 提高首屏加载时间
3 实现思路
3.1 按需加载
使用v-for渲染展示可视区的数据
v-for="item in visibleData"
因此关键点是:确定 visibleData
计算属性中定义:怎样获取可视区的数据 visibleData
:
visibleData(){
return this.listData.slice(this.start, Math.min(this.end,this.listData.length)); // Math.min防止页面滑过列表了
}
// 对源数组listData截取,截取长度是start,end位置
start
可视区域数据的起始索引 end
可视区域数据的结束索引
this.start = Math.floor(scrollTop / this.itemSize); // 卷去的区域 除 每格长度 = 开始的索引
this.end = this.start + this.visibleCount; // visibleCount可显示的列表项数
visibleCount == this.screenHeight / this.itemSize // 可显示的列表项数 = 屏幕长度/每格长度
关键逻辑就如上所示,当然,可视区域是上下移动的,我们要动态改变start、end的值
在最外层div绑定滚动事件
<div ......@scroll="scrollEvent($event)".....
scrollEvent() {
//当前滚动位置 卷去的区域
let scrollTop = this.$refs.list.scrollTop; // .scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数
//此时的开始索引
this.start = Math.floor(scrollTop / this.itemSize);
//此时的结束索引
this.end = this.start + this.visibleCount;
//此时的偏移量
this.startOffset = scrollTop - (scrollTop % this.itemSize);
}
到此就是其按需加载的主要逻辑
3.2 translate3d() 移动纵轴
translate3d() CSS 函数在 3D 空间内移动一个元素的位置。参数:横坐标、纵坐标、z坐标
这里需要给列表绑定纵轴的偏移量,来改变列表的纵坐标,如果偏移量设置错误,上下滚动列表,仅仅数据改变,没有列表上下移动,体验感很差
在长列表的 div 上,绑定样式
:style="{ transform: getTransform }"
getTransform 在计算属性中
getTransform(){
return `translate3d(0,${this.startOffset}px,0)`;
},
startOffset值,当滚动事件触发,会更新value
this.startOffset = scrollTop - (scrollTop % this.itemSize);
3.3 完整代码
移步github:
https://github.com/Snake-c/virtual_list
4 不足之处
- 虚拟列表只针对渲染过程的优化。全部数据依然是从后端接口直接拿过来的,如果数据量过大的话,采用分页从后端拿部分数据的方法不妨更好
- 上述方法的条件是列表项高度相同,在后续会更新解决方法