把以下代码拷贝放到html文件中即可查看效果
vue.js 文件需要自己引入
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>虚拟列表</title>
<style>
.container {
width: 300px;
height: 370px;
overflow: auto;
border: 1px solid;
margin: 100px auto;
}
.item {
height: 39px;
line-height: 30px;
border-bottom: 1px solid #aaa;
padding-left: 20px;
}
</style>
</head>
<body>
<div id="app">
<button @click="add">增加</button>
<div class="container" ref="container">
<div class="scroll-wrapper" :style="style">
<div v-for="(item, index) in scrollList" :key="index" class="item">{{item}}</div>
</div>
</div>
</div>
<!-- vue自行引入 -->
<script src="../vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
list: [],
itemLen: 40, //每一项高度
startIndex: 0,
endIndex: 0,
paddingTop: 0,
paddingBottom: 0,
allHeight: 0, //所有数据的高度
},
computed: {
scrollList() {
//截取要展示的数据
return this.list.slice(this.startIndex, this.endIndex)
},
style() {
//获取内容体的上下padding
return {
paddingTop: this.paddingTop + 'px',
paddingBottom: this.paddingBottom + 'px'
}
}
},
mounted() {
const needLen = Math.ceil(370 / this.itemLen) + 1;
this.endIndex = needLen;
this.add();
const container = this.$refs.container;
this.timer = null;
//利用外层div的高度 和 每一项的高度,获取可视区域需要展示的数据条数
container.addEventListener('scroll', () => {
//防抖
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
const top = container.scrollTop;
console.log(top);
//当列表滚动到任何一个位置,利用滚动条距离顶部的值算出需要展示数据的起止位置
this.startIndex = Math.floor(top / this.itemLen)
this.endIndex = this.startIndex + needLen;
//重新设置上下边距
this.paddingTop = this.startIndex * this.itemLen;
if (this.list.length >= this.endIndex) {
this.paddingBottom = (this.list.length - this.endIndex) * this.itemLen;
} else {
this.paddingBottom = 0;
}
}, 20);
})
},
methods: {
add() {
let arr = new Array(30).fill(0)
let basis = this.list.length;
arr = arr.map((item, index) => {
return index + 1 + basis
})
this.list = [
...this.list,
...arr
];
//插入数据,重新设置下边距
const valLen = this.list.length
this.allHeight = valLen * this.itemLen
this.paddingBottom = this.allHeight - this.endIndex * this.itemLen
}
}
})
</script>
</body>
</html>