一、新建一个virtual-list.vue
<template>
<!-- 虚拟列表 -->
<view>
<scroll-view :scroll-top="scrollTop" class="scroll-container" scroll-y="true" @scroll="scrollEvent"
:style="{ height: containerHeight }">
<!--可视区域里所有数据的渲染区域-->
<view class="list" :style="{ top: top + 'px', ...customStyle }">
<!--单条数据渲染区域-->
<view v-for="(item, index) in showList" :key="index">
<slot name="item" :row="item"></slot>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
// 使用示例
// <virtual-list :sourceData="listAll" containerHeight="calc(100vh - 196rpx)" :itemHeight="200" :showNum="5" :customStyle="{ padding: '30rpx' }">
// <template v-slot:item="{ row }">
// ......your code
// </template>
// </virtual-list>
// 刷新组件
// this.$refs.virtualList.refresh()
export default {
props: {
// 数据源
sourceData: {
type: Array,
default: () => [],
required: true
},
// 滚动容器总高度
containerHeight: {
type: String,
default: '200px',
},
//每条数据所占高度
itemHeight: {
type: Number,
default: 200,
required: true
},
//每次加载到可视区域的数量,itemHeight X showNum 要大于可视区域高度 ,否则页面滚动不了
showNum: {
type: Number,
default: 10,
required: true
},
// 自定义列表样式
customStyle: {
type: Object,
default: () => ({})
}
},
data() {
return {
showList: [], //可视区域显示的数据
top: 0, //偏移量
scrollTop: 0, //卷起的高度
startIndex: 0, //可视区域第一条数据的索引
endIndex: 0, //可视区域最后一条数据后面那条数据的的索引,因为后面要用slice(start,end)方法取需要的数据,但是slice规定end对应数据不包含在里面
}
},
created() {
//计算可视区域数据
this.getShowList()
},
methods: {
//计算可视区域数据
getShowList() {
this.startIndex = Math.floor(this.scrollTop / this.itemHeight) //可视区域第一条数据的索引
this.endIndex = this.startIndex + this.showNum //可视区域最后一条数据的后面那条数据的索引
this.showList = this.sourceData.slice(this.startIndex, this.endIndex) //可视区域显示的数据,即最后要渲染的数据。实际的数据索引是从this.startIndex到this.endIndex-1
this.top = this.scrollTop - (this.scrollTop % this.itemHeight) //在这需要获得一个可以被itemHeight整除的数来作为item的偏移量,这样随机滑动时第一条数据都是完整显示的
},
//区域滚动事件
scrollEvent(e) {
this.scrollTop = e.detail.scrollTop
this.getShowList()
},
// 刷新组件
refresh() {
setTimeout(() => {
this.getShowList()
this.scrollTop = 0
})
}
}
}
</script>
<style scoped lang='scss'>
.scroll-container {
position: relative;
width: 100%;
.list {
position: absolute;
width: 100%;
}
}
</style>
二、使用(下方代码是我使用的场景,你们可以自定义插槽中的内容)
<virtual-list ref="virtualList" :sourceData="taskList" containerHeight="calc(100vh - 196rpx)" :itemHeight="200"
:showNum="5" :customStyle="{ padding: '30rpx' }">
<template v-slot:item="{ row }">
<view class="card">
<view class="title">公章申请</view>
<view class="row">
<view class="fileds">创建日期:</view>
<view class="content">2022-09-18 23:20:14</view>
</view>
<view class="row">
<text class="fileds">申请人:</text>
<text class="content">{{ row.name }}</text>
</view>
<view class="entry">
<div class="name">查看详情</div>
<div class="icon">></div>
</view>
</view>
</template>
</virtual-list>
三、参数说明
属性
sourceData:接收列表数据,传入数组即可
containerHeight:滚动容器的高度,接收例如 200px 的字符串
itemHeight:每条数据所占高度,传入数字,尽量在每一行的高度一致的列表使用,行高度差距非常大时不建议使用
showNum:滚动列表中能看到的行数量,保证 showNum * itemHeight 大于 containerHeight 即可,可以自行调整数值,滚动顺滑即可
customStyle:自定义列表样式,接收style对象
方法
组件上定义ref="virtualList"
比例tab切换列表重新赋值后使用this.$refs.virtualList.refresh()刷新列表即可
作用域插槽
item
参数row, 数组遍历后单项的数据