基于老分享 云中桥 前端进阶 高性能渲染十万条数据(虚拟列表),改版了uniapp版的虚拟滚动列表,目前暂未对性能进行测试,只做了demo版,供大家参考。
-
主要思路
虚拟滚动列表在首屏加载时只加载可视化区域内需要显示的内容,在滚动时动态计算开始下标、结束下标,展示对应展示数据,始终保持较少的Dom数量。
-
主要数据字段
screenHeight
屏幕高度即可视区域高度startOffset
顶部偏移量startIndex
可视化区域的数据开始下标endIndex
可视化区域的数据结束下标
-
具体实现
- 模板
使用scroll-view 进行滚动区域设置,同时方便scroll获取滚动距离 scrollTop,视口高度为100vh。list-phantom:获取数据的总高度,展示竖向条,list内展示主要内容。
<scroll-view ref='list' scroll-y="true" class='list-container' @scroll="handleScroll" style="height: 100vh;"> <div class='list-phantom' :style="{ height: listHeight + 'px' }"></div> <div class='list' :style="{ transform: getTransform }"> <div v-for="(item,index) in visibleData" class='list-item' :key='item.id' :style="{height:itemSize+'px',lineHeight:itemSize+'px'}"> {{item.value}} </div> </div> </scroll-view>
2. 模板首先获取屏幕高度,计算展示屏幕可视化区域数量,同时计算总高度// 获取屏幕高度 getScreenHeight(){ const _this=this uni.getSystemInfo({ success: function (res) { _this.screenHeight=res.screenHeight } }); },
// 可显示的列表项数(itemSize为props传入的项目高度) 总高度 computed:{ //可显示的列表项数 visibleCount(){ return Math.ceil(this.screenHeight / this.itemSize) }, //列表总高度 listHeight(){ return this.listData.length * this.itemSize; }, //偏移量对应的style getTransform(){ return `translate3d(0,${this.startOffset}px,0)`; }, //获取真实显示列表数据 visibleData(){ return this.listData.slice(this.startIndex, Math.min(this.endIndex,this.listData.length)); } }
// 计算可视化区域要展示的数据的开始与结束索引 mounted() { this.getScreenHeight() this.startIndex = 0; this.endIndex = this.startIndex + this.visibleCount; },
3. 滚动时根据scrollTop计算开始与结束索引以及顶部偏移量handleScroll(e){ //当前滚动位置 let scrollTop = e.detail.scrollTop; //开始索引 this.startIndex = Math.floor(scrollTop / this.itemSize); //结束索引 this.endIndex = this.startIndex + this.visibleCount; //顶部偏移量 this.startOffset = scrollTop - (scrollTop % this.itemSize); }
4. 设置顶部偏移量<div class='list' :style="{ transform: getTransform }"></div> computed:{ //偏移量对应的style getTransform(){ return `translate3d(0,${this.startOffset}px,0)`; } },