virtalList.vue 虚拟滚动组件简单实现
实现思路
- 能滚动的盒子 container
- scroll-bar 滚动条,滚动条的高度 barHeight = this.size(每条数据的高度) * this.visibleData.length(总数据条数) + 'px'
- scroll-list容器,真实显示的列表容器。listTop 记录列表占据滚动条的高度,确保scroll-list一直在可视范围内。
- visibleData 总的数据 size 每条数据的高度 listTop 记录列表占据滚动条的高度 showNumber 每页展示的条数 start 数据截取的开始位置 end = start + showNumber 数据截取的结束位置
- handlScroll方法 滚动的时候记录滚动高度 const scrollTop = this.$refs.container.scrollTop; 动态计算start = Math.floor(scrollTop / size),向下取整。end = start + showNumber,动态截取可显示的数据条数 showData = this.visibleData.slice(this.start, this.end)
<template>
<!-- 能滚动的盒子 -->
<div class="container" ref="container" @scroll="handlScroll">
<div class="scroll-bar" :style="{ height: barHeight }" ref="scrollbar"></div>
<div class="scroll-list" :style="{top: listTop}">
<div v-for="item in showData" :style="{ height: size + 'px' }" ref="items" :key="item.id">
<slot :item="item"></slot>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
visibleData: {
type: Array,
default: () => {}
},
size: {
type: Number,
default: 0
},
showNumber: {
type: Number,
default: 0
}
},
data() {
return {
start: 0,
end: this.showNumber,
}
},
computed: {
showData() {
return this.visibleData.slice(this.start, this.end)
},
barHeight() {
return this.visibleData.length * this.size + 'px'
},
listTop() {
return this.start * this.size + 'px'
},
},
methods: {
handlScroll() {
const scrollTop = this.$refs.container.scrollTop;
this.start = Math.floor(scrollTop / this.size);
this.end= this.start + this.showNumber;
},
}
}
</script>
<style>
.container {
overflow-y: scroll;
position: relative;
background: #eee;
width: 100%;
height: 100vh;
}
.scroll-list {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
使用virtalList组件
import virtalList from './virtalList.vue'
<virtalList :size="40" :showNumber="30" :visibleData="visibleData">
<template #default="{ item }">
<div>{{ item.content }}</div>
</template>
</virtalList>