vue自定义实现虚拟化列表
1使用
<ViualList :size="40" :remain="8" :dataList="dataList"> </ViualList>
size:每个列表的高度Height
remain:当前屏幕展示数据个数
dataList:当前数据
2自定义组件ViualList
根据size和remain确定内容区域height
根据size和dataList长度确定滚动条height
<!-- 主高度 -->
<div class="vitual-con" ref="vitualConRef" @scroll="handleScroll">
<!-- 滚动条 -->
<div class="scroll-bar" ref="scrollBarRef"></div>
<div
class="scroll-list"
ref="scrollListRef"
:style="{ 'padding-top': `${this.scrollTop}px` }"
>
<div
class="listItem"
v-for="item in visibleData"
:key="item.id"
:style="{ height: `${size}px` }"
>
{{ item.id + "." + item.value }}
</div>
</div>
</div>
...... mounted() { //定义主屏幕高度 this.$refs.vitualConRef.style.height = this.size * this.remain + "px"; //定义滚动条高度 this.$refs.scrollBarRef.style.height = this.size * this.dataList.length + "px"; },
.vitual-con {
overflow-y: scroll;
position: relative;
}
.scroll-list {
position: absolute;
top: 0;
left: 0;
}
控制当前页面只显示remain个数的数据可以根据滚动条来获取当前位置和数据
handleScroll() { this.start = Math.floor(this.$refs.vitualConRef.scrollTop / this.size); this.end = this.start + this.remain; },
在字符串中截取start到end数据,优化效果则设置预留数据
computed: { visibleData() { let start = this.start - this.preveCount; let end = this.end + this.nextCount; return this.dataList.slice(start, end); }, // 计算内容区域 当前距离顶部的距离----优化 scrollTop() { return this.start * this.size - this.size * this.preveCount; }, // 优化-----避免下方出现的空白和当用户快速滚动时,出现空白屏----解决:预留加载 preveCount() { // 前面预留的个数---- 当前面的个数小于 8 个时,有几个就预留几个 return Math.min(this.start, this.remain); }, nextCount() { // 后面预先加载的个数 return Math.min(this.end, this.dataList.length - this.end); }, },
以下是完整代码
<template>
<!-- 主高度 -->
<div class="vitual-con" ref="vitualConRef" @scroll="handleScroll">
<!-- 滚动条 -->
<div class="scroll-bar" ref="scrollBarRef"></div>
<div
class="scroll-list"
ref="scrollListRef"
:style="{ 'padding-top': `${this.scrollTop}px` }"
>
<div
class="listItem"
v-for="item in visibleData"
:key="item.id"
:style="{ height: `${size}px` }"
>
{{ item.id + "." + item.value }}
</div>
</div>
</div>
</template>
<script>
export default {
name: "ViualList",
props: {
size: {
type: Number,
default: 40,
},
remain: {
type: Number,
default: 8,
},
dataList: {
type: Array,
default: () => [],
},
},
data() {
return {
start: 0,
end: this.remain,
};
},
computed: {
visibleData() {
let start = this.start - this.preveCount;
let end = this.end + this.nextCount;
return this.dataList.slice(start, end);
},
// 计算内容区域 当前距离顶部的距离----优化
scrollTop() {
return this.start * this.size - this.size * this.preveCount;
},
// 优化-----避免下方出现的空白和当用户快速滚动时,出现空白屏----解决:预留加载
preveCount() {
// 前面预留的个数---- 当前面的个数小于 8 个时,有几个就预留几个
return Math.min(this.start, this.remain);
},
nextCount() {
// 后面预先加载的个数
return Math.min(this.end, this.dataList.length - this.end);
},
},
mounted() {
//定义主屏幕高度
this.$refs.vitualConRef.style.height = this.size * this.remain + "px";
//定义滚动条高度
this.$refs.scrollBarRef.style.height =
this.size * this.dataList.length + "px";
},
methods: {
handleScroll() {
// console.log(this.$refs.vitualConRef.scrollTop);
this.start = Math.floor(this.$refs.vitualConRef.scrollTop / this.size);
this.end = this.start + this.remain;
},
},
};
</script>
<style>
.vitual-con {
overflow-y: scroll;
position: relative;
}
.scroll-list {
position: absolute;
top: 0;
left: 0;
}
</style>

浙公网安备 33010602011771号