我写了一个代码实现了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>
网友回复