描述
【前端性能优化】使用虚拟列表优化长列表,本文基于vue2实现
思路
- 创建虚拟列表容器,容器内包括:
- 显示列表(此列表截取数据list需要显示的部分+前后多展示若干项)
- 一个空dom,高度根据数据list的项 * 每项高度算出,为了撑开父容器模拟滚动
2、监听虚拟列表容器滚动事件,调整显示列表的定位,使其永远覆盖在虚拟列表容器的上方
实现
<script>
const throttle = (fn, delay) => {
let stratTimer
let endTimer
return function() {
var args = Array.prototype.slice.call(arguments, 1)
if (stratTimer) {
return
}
stratTimer = setTimeout(() => {
clearTimeout(stratTimer)
stratTimer = null
endTimer = setTimeout(() => {
clearTimeout(endTimer)
endTimer = null
fn.apply(this, args)
}, delay)
}, delay)
if (endTimer) {
return
}
fn.apply(this, args)
}
}
export default {
data() {
return {
list: [],
itemHeight: 20,
size: 20,
start: 0,
end: 20,
offset: 40, // 显示列表前后多预置的项目
}
},
computed: {
// 显示列表需要前后多预置多几项,防止滚动白屏问题
showList() {
const list = this.list.slice(this.start, this.end)
// 显示列表预制
// 列表前预制
for (let i = 1; i <= this.offset; i++) {
list.unshift(this.list[this.start-i] || '')
}
// 列表后预制,若已到达数据列表最底部,不再预制
for (let i = 1; i <= this.offset; i++) {
if (this.end + i <= this.list.length) {
list.push(this.list[this.end - 1 + i])
}
}
return list
}
},
methods: {
handleScroll: throttle(function() {
const scrollTop = this.$refs.scroll.scrollTop
this.start = Math.floor(scrollTop / this.itemHeight)
this.end = this.start + this.size
}, 100)
},
mounted() {
for (let i = 1; i <= 10000; i++) {
this.list.push(i)
}
}
}
</script>
<template>
<div ref="scroll" class="vs-list-container" :style="{height: itemHeight * size + 'px'}" @scroll="handleScroll">
<div class="vs-list-scroll" :style="{height: itemHeight * list.length + 'px'}"></div>
<div class="vs-list" :style="{top: itemHeight * (start - offset) + 'px'}">
<div class="vs-list-item" v-for="(item, index) in showList" :key="index">{{item}}</div>
</div>
</div>
</template>
<style scoped>
.vs-list-container {
position: relative;
box-sizing: border-box;
width: 200px;
border: solid 1px #000000;
overflow-y: auto;
}
.vs-list {
position: absolute;
top: 0;
left: 0;
right: 0;
}
.vs-list-item {
height: 20px;
width: 100%;
}
</style>
存在问题
1、虚拟列表快速拖动白屏问题,通过在显示列表前后多预置若干项来解决
2、未解决:虚拟列表瞬间拖动到底部还是存在白屏问题,原因是显示列表预制的项没有拖动的高度多