我写了一个代码实现了uniapp的虚拟列表滚动加载,
代码说明:
totalItems:整个列表的数据,示例中用的是 1000 条数据。
visibleItemCount:设定在可视区域最多显示的条目数。
buffer:设定滚动缓冲区,这样可以在实际滚动时减少抖动。
visibleItems:计算当前需要显示的条目,截取 totalItems 的一部分。
topBlankHeight 和 bottomBlankHeight:计算上下两部分占位的空白高度
<template>
<view class="container">
<scroll-view
class="scroll-view"
scroll-y
@scroll="onScroll"
:scroll-top="scrollTop"
>
<!-- 占位的顶部空白区域 -->
<view :style="{ height: topBlankHeight + 'px' }"></view>
<!-- 实际显示的内容 -->
<view
v-for="(item, index) in visibleItems"
:key="item.id"
class="item"
>
{{ item.text }}
</view>
<!-- 占位的底部空白区域 -->
<view :style="{ height: bottomBlankHeight + 'px' }"></view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
totalItems: [], // 原始数据
itemHeight: 60, // 每个item的高度
visibleItemCount: 15, // 可视区域最多显示的item数量
buffer: 10, // 缓冲区,较大缓冲减少抖动
startIdx: 0, // 可视区域起始索引
scrollTop: 0, // 滚动位置
};
},
computed: {
visibleItems() {
return this.totalItems.slice(
this.startIdx,
this.startIdx + this.visibleItemCount + this.buffer
);
},
topBlankHeight() {
return this.startIdx * this.itemHeight;
},
bottomBlankHeight() {
const remainingItems = this.totalItems.length - (this.startIdx + this.visibleItems.length);
return remainingItems * this.itemHeight;
},
},
methods: {
onScroll: throttle(function (e) {
const scrollTop = e.detail.scrollTop;
const currentIdx = Math.floor(scrollTop / this.itemHeight);
// 仅在距离足够大时更新startIdx,避免频繁更新
if (Math.abs(currentIdx - this.startIdx) > this.buffer / 2) {
this.startIdx = currentIdx - this.buffer / 2;
this.startIdx = Math.max(0, this.startIdx);
}
this.scrollTop = scrollTop;
}, 50), // 使用50ms的节流以减少频繁刷新
},
mounted() {
// 初始化数据
this.totalItems = Array.from({ length: 1000 }, (_, i) => ({
id: i + 1,
text: `Item ${i + 1}`,
}));
},
};
// 节流函数:限制函数在指定时间内只能执行一次
function throttle(func, delay) {
let last = 0;
return function (...args) {
const now = new Date().getTime();
if (now - last > delay) {
last = now;
return func.apply(this, args);
}
};
}
</script>
<style>
.container {
height: 100vh;
}
.scroll-view {
height: 100%;
}
.item {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid #ddd;
}
</style>
网友回复


