后端一次返回数据过多,或者向下滚动过程会叠加渲染产生的新数据,会导致页面的 dom 元素越来越多,慢慢也就会变的有卡顿的感觉,于是想到使用虚拟列表。只渲染用户看到的数据,操作过程中不停更新用户看到的数据。
1.定义变量
data() {
return {
fleetAll: [], // 列表全部数据
fleetShowList: [], // 列表全部数据中需要的渲染数据
fleetScrollTop: 0, // 父级 y 轴 scroll 滚动距离
fleetBoxHeight: 12*32, // 父级元素的高度 默认渲染12条
}
},
2.template 模板
<div class="h300 pr ova" @scroll="scrollFleet">
<div :style="'height: '+fleetBoxHeight+'px;'">
<div class="lin32 hover pa l0" :style="'top: '+item.top+'px;'" v-for="(item, keys) in fleetShowList" :key="item.id">{{ item.name }}</div>
</div>
</div>
3. 函数处理
// 初始化数据
initData() {
let fleetList = []
for (let i=1;i<200;i++) {
fleetList.push({id: String(i), name: '车队'+String(i).padStart(3, '0')+'车队'})
}
this.fleetBoxHeight = fleetList.length*32
this.fleetAll = fleetList
},
// scroll 事件处理
scrollFleet(e) {
this.fleetScrollTop = e.target.scrollTop
this.handleFleetShowList()
},
// scroll 过程中渲染数据处理
handleFleetShowList() {
let oldStartIdx = this.startIdx
// 防止滚动到最下面时如果滚动距离超过最大可滚动距离,会出现最后一个元素定位超出,导致一直可以滚动
if (this.fleetBoxHeight>300 && this.fleetScrollTop>(this.fleetBoxHeight-300)) {
this.fleetScrollTop = (this.fleetBoxHeight-300)
}
this.startIdx = Math.floor(this.fleetScrollTop / 32)
let fleet12 = []
let fl = fleet12.length
while (fl<12 && (this.startIdx+fl)<this.fleetAll.length) {
let fitem = this.fleetAll[this.startIdx+fl]
if (oldStartIdx != this.startIdx) {
fitem.top = this.fleetScrollTop+(fl*32)
}
// 向上滚动到第一条数据时,可能存在第一条数据有定位距离,如果接着向上滚动,则清空第一条定位距离
if (oldStartIdx == 0 && this.startIdx == 0) {
fitem.top = fl*32
}
fleet12.push(fitem)
fl = fleet12.length
}
this.fleetShowList = fleet12
},