更新记录
0.0.4(2026-02-28) 下载此版本
- 嵌套滚动模式适配微信小程序
0.0.3(2026-02-28) 下载此版本
- 增加嵌套滚动模式,支付页面滚动模式
0.0.2(2026-02-28) 下载此版本
重构插件版本
查看更多平台兼容性
uni-app(4.55)
| Vue2 | Vue2插件版本 | Vue3 | Vue3插件版本 | Chrome | Chrome插件版本 | Safari | Safari插件版本 | app-vue | app-vue插件版本 | app-nvue | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 0.0.2 | √ | 0.0.2 | √ | 0.0.2 | √ | 0.0.2 | √ | 0.0.2 | - | √ | 0.0.2 | √ | 0.0.2 | - |
| 微信小程序 | 微信小程序插件版本 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 0.0.2 | - | - | - | - | - | - | - | - | - | - | - |
zhibai-virtualList
一个支持 uniapp 的虚拟列表组件,兼容微信小程序、H5 和 APP 环境,同时支持 Vue2 和 Vue3。
功能特性
- ✅ 虚拟列表加载,优化性能
- ✅ 支持动态高度和固定高度
- ✅ 支持双列瀑布流布局
- ✅ 兼容微信小程序、H5、APP 环境
- ✅ 同时支持 Vue2 和 Vue3
- ✅ 支持加载状态和完成状态显示
- ✅ 智能数据追加,无缝衔接新数据
使用方法
全局注册
import zhibaiVirtualList from 'zhibai-virtual-list'
Vue.use(zhibaiVirtualList)
局部引入
<template>
<zhibai-virtualList
:list="dataList"
:item-height="100"
:mode="'single'"
:loading="loading"
:finished="finished"
@loadMore="handleLoadMore"
>
<template #default="{ item, index }">
<view class="item">{{ item.title }}</view>
</template>
</zhibai-virtualList>
</template>
<script>
import zhibaiVirtualList from 'zhibai-virtual-list'
export default {
components: {
zhibaiVirtualList
},
data() {
return {
dataList: [],
loading: false,
finished: false
}
},
methods: {
handleLoadMore() {
if (this.loading || this.finished) return
this.loading = true
// 模拟加载数据
setTimeout(() => {
const newData = [] // 获取新数据
this.dataList = [...this.dataList, ...newData]
this.loading = false
// 如果没有更多数据
if (newData.length === 0) {
this.finished = true
}
}, 1000)
}
}
}
</script>
自定义加载状态
<template>
<zhibai-virtualList
:list="dataList"
:loading="loading"
:finished="finished"
@loadMore="handleLoadMore"
>
<template #default="{ item, index }">
<view class="item">{{ item.title }}</view>
</template>
<!-- 自定义加载状态 -->
<template #loading>
<view class="custom-loading">加载中...</view>
</template>
<!-- 自定义完成状态 -->
<template #finished>
<view class="custom-finished">没有更多了</view>
</template>
</zhibai-virtualList>
</template>
Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| list | 数据列表 | Array | [] |
| itemHeight | 固定高度模式下的项目高度(为0时使用动态高度) | Number | 0 |
| mode | 布局模式:'single'(单列) / 'waterfall'(双列瀑布流) | String | 'single' |
| estimatedHeight | 动态高度模式下的预估高度 | Number | 100 |
| bufferSize | 缓冲区大小(渲染可视区域外的项目数量) | Number | 5 |
| height | 容器高度(为0时自动获取屏幕高度) | Number | 0 |
| loading | 是否正在加载 | Boolean | false |
| finished | 是否已加载完成 | Boolean | false |
| scrollYShow | 是否允许纵向滚动 | Boolean | true |
| usePageScroll | 是否使用页面滚动模式(不使用scroll-view) | Boolean | false |
| externalScroll | 是否外部控制滚动(嵌套在父级scroll-view中) | Boolean | false |
| parentScrollSelector | 父级scroll-view的选择器(externalScroll时使用) | String | '' |
| containerSelector | 组件容器的选择器(用于嵌套滚动时查询偏移量,微信小程序推荐使用) | String | '' |
| disableBounce | 是否禁用滚动弹性效果(不影响滚动穿透) | Boolean | false |
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| loadMore | 滚动到底部时触发(用于加载更多) | - |
| scrollToUpper | 滚动到顶部时触发 | - |
Slots
| 插槽名 | 说明 | 参数 |
|---|---|---|
| default | 列表项内容 | { item, index } |
| loading | 自定义加载状态 | - |
| finished | 自定义加载完成状态 | - |
使用说明
固定高度模式
当所有列表项高度相同时,设置 itemHeight 可以获得最佳性能:
<zhibai-virtualList
:list="dataList"
:item-height="80"
mode="single"
>
<template #default="{ item }">
<view style="height: 80px">{{ item.title }}</view>
</template>
</zhibai-virtualList>
动态高度模式
当列表项高度不固定时,设置 estimatedHeight 预估高度:
<zhibai-virtualList
:list="dataList"
:estimated-height="100"
mode="single"
>
<template #default="{ item }">
<view>{{ item.content }}</view>
</template>
</zhibai-virtualList>
瀑布流模式
双列瀑布流布局,适合图片列表:
<zhibai-virtualList
:list="dataList"
:estimated-height="150"
mode="waterfall"
>
<template #default="{ item }">
<view>
<image :src="item.image" />
<text>{{ item.title }}</text>
</view>
</template>
</zhibai-virtualList>
页面滚动模式
使用页面原生滚动,而不是 scroll-view 局部滚动:
<template>
<view>
<zhibai-virtualList
ref="virtualList"
:list="dataList"
:use-page-scroll="true"
:estimated-height="100"
@loadMore="handleLoadMore"
>
<template #default="{ item }">
<view>{{ item.content }}</view>
</template>
</zhibai-virtualList>
</view>
</template>
<script>
export default {
// 小程序和APP需要在页面中添加
onPageScroll(e) {
// 调用组件的handlePageScroll方法
if (this.$refs.virtualList) {
this.$refs.virtualList.handlePageScroll(e)
}
}
}
</script>
页面滚动模式说明:
- ✅ 使用页面原生滚动,性能更好
- ✅ 自动支持下拉刷新等页面级功能
- ✅ H5环境自动监听window滚动
- ⚠️ 小程序/APP需要在页面的
onPageScroll中手动调用组件方法 - ⚠️ 需要给组件添加
ref属性
嵌套滚动模式
当虚拟列表需要嵌套在父级 scroll-view 中时使用:
1. 嵌套在原生 scroll-view 中
<template>
<view class="page">
<!-- 外层scroll-view -->
<scroll-view
id="parentScroll"
class="parent-scroll"
scroll-y
@scroll="handleParentScroll"
>
<!-- 页面头部内容 -->
<view class="header">
<text>页面头部</text>
</view>
<!-- 嵌套的虚拟列表 -->
<zhibai-virtualList
ref="virtualList"
:list="dataList"
:external-scroll="true"
parent-scroll-selector="#parentScroll"
:estimated-height="120"
:loading="loading"
:finished="finished"
@loadMore="handleLoadMore"
>
<template #default="{ item }">
<view>{{ item.content }}</view>
</template>
</zhibai-virtualList>
<!-- 页面底部内容 -->
<view class="footer">
<text>页面底部</text>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
methods: {
// 处理父级scroll-view滚动
handleParentScroll(e) {
// 将滚动事件传递给虚拟列表组件
if (this.$refs.virtualList) {
this.$refs.virtualList.handlePageScroll(e.detail)
}
},
handleLoadMore() {
// 加载更多数据
}
}
}
</script>
2. 嵌套在 z-paging 等第三方组件中
<template>
<view class="page">
<!-- z-paging 组件 -->
<z-paging
ref="paging"
id="pagingPage"
@scroll="handlePagingScroll"
:use-page-scroll="false"
>
<!-- 嵌套的虚拟列表 -->
<zhibai-virtualList
ref="virtualList"
:list="dataList"
:external-scroll="true"
parent-scroll-selector="#pagingPage"
:estimated-height="120"
:loading="loading"
:finished="finished"
@loadMore="handleLoadMore"
>
<template #default="{ item }">
<view>{{ item.content }}</view>
</template>
</zhibai-virtualList>
</z-paging>
</view>
</template>
<script>
export default {
methods: {
// 处理z-paging滚动
handlePagingScroll(e) {
// 将滚动事件传递给虚拟列表组件
if (this.$refs.virtualList) {
this.$refs.virtualList.handlePageScroll(e.detail)
}
},
handleLoadMore() {
// 加载更多数据
}
}
}
</script>
嵌套滚动模式说明:
- ✅ 支持虚拟列表嵌套在父级 scroll-view 中
- ✅ 支持嵌套在 z-paging 等第三方滚动组件中
- ✅ 自动计算组件相对于父级的偏移量
- ✅ 正确处理滚动位置和触底加载
- ⚠️ 需要设置
external-scroll="true" - ⚠️ 需要提供
parent-scroll-selector指定父级选择器(使用ID选择器,如#pagingPage) - ⚠️ 需要在父级的
@scroll事件中调用组件的handlePageScroll方法 - ⚠️ 需要给组件添加
ref属性 - ⚠️ 如果父级是 z-paging 等封装组件,确保给父级组件添加
id属性
注意事项
- 动态高度模式下,组件会自动查询实际高度并更新,首次渲染可能会有轻微的位置调整
- 瀑布流模式下,数据会根据高度自动分配到左右两列
- 使用
loading和finished属性可以控制加载状态的显示 - 新数据通过数组追加的方式添加(
[...oldList, ...newList]),组件会自动处理衔接 - 微信小程序中,瀑布流模式的key使用了前缀('left-'/'right-')来避免slot重复警告
- 使用
disableBounce可以禁用滚动弹性效果,同时保留滚动穿透功能 - 页面滚动模式下,小程序和APP需要在页面的
onPageScroll中手动调用组件的handlePageScroll方法 - 嵌套滚动模式下,需要在父级 scroll-view 的
@scroll事件中调用组件的handlePageScroll方法 - 三种滚动模式互斥:
- 默认模式:使用组件内部的 scroll-view
- 页面滚动模式:
usePageScroll="true",使用页面原生滚动 - 嵌套滚动模式:
externalScroll="true",嵌套在父级 scroll-view 中
常见问题
嵌套在 z-paging 等第三方组件中
如果虚拟列表嵌套在 z-paging、uview 的 scroll-view 等第三方封装组件中:
- 确保父级组件有 ID:给父级组件添加唯一的
id属性 - 传递正确的选择器:使用 ID 选择器,如
parent-scroll-selector="#pagingPage" - 监听滚动事件:在父级组件的
@scroll事件中调用虚拟列表的handlePageScroll方法 - 父级组件查询失败:由于 z-paging 等是封装组件,无法直接查询到其位置信息,组件会自动使用虚拟列表自身的位置作为偏移量。这种情况下:
- 确保在父级的
@scroll事件中正确传递e.detail.scrollTop - 如果显示不正常,检查传递的 scrollTop 值是否正确
- 可以在控制台查看
[嵌套滚动]相关的日志信息
- 确保在父级的
z-paging 示例代码(推荐使用 containerSelector):
<template>
<z-paging
ref="paging"
id="pagingPage"
@scroll="handlePagingScroll"
:use-page-scroll="false"
>
<!-- 使用 view 包裹组件,并提供 containerSelector -->
<view class="defaGoodList">
<zhibai-virtualList
ref="virtualList"
:list="dataList"
:external-scroll="true"
parent-scroll-selector="#pagingPage"
container-selector=".defaGoodList"
:estimated-height="120"
@loadMore="loadMore"
>
<template #default="{ item }">
<view>{{ item.content }}</view>
</template>
</zhibai-virtualList>
</view>
</z-paging>
</template>
<script>
export default {
methods: {
handlePagingScroll(e) {
// 关键:正确传递 scrollTop
if (this.$refs.virtualList) {
this.$refs.virtualList.handlePageScroll(e.detail)
}
},
loadMore() {
// 加载更多数据
}
}
}
</script>
注意事项:
- 推荐使用
containerSelector:在组件外包裹一个 view,并通过container-selector传入选择器(如.defaGoodList) - 微信小程序无法直接查询自定义组件内部元素,使用容器选择器可以准确获取偏移量
- z-paging 的
@scroll事件需要设置:use-page-scroll="false"才会触发 - 确保
e.detail包含scrollTop属性 - 如果不使用
containerSelector,组件会尝试使用类名查询,但可能不够准确
微信小程序slot警告
如果遇到 "More than one slot named" 警告,这是因为微信小程序无法循环slot,有以下几种解决方案:
- 使用Skyline 渲染引擎,它支持循环slot,只要在使用的页面
options中添加{"dynamicSlots": true}中即可,因为Skyline 渲染引擎实在BUG太多所以没有实践,具体可以参考 动态 slot - 不使用循环slot,而是使用条件渲染来实现,例如:
<!-- 父组件 --> <zhibai-virtualList :list="dataList" :estimated-height="150" mode="waterfall" > <!-- #ifndef MP-WEIXIN --> <template #default="{ item, index }"> <goodInfo goodsComType="falls" :item="item"></goodInfo> </template> <!-- #endif --> </zhibai-virtualList>
<!-- zhibai-virtualList 组件 -->
<!-- #ifdef MP-WEIXIN -->
<goodInfo goodsComType="falls" :item="item._data"></goodInfo>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<slot :item="item._data" :index="item._index"></slot>
<!-- #endif -->
- 使用抽象节点,具体可以参考 微信抽象节点
iOS滚动弹性效果
组件使用 scroll-view 的原生 bounces 属性来控制滚动弹性效果:
<!-- 禁用弹性效果(橡皮筋效果),同时保留滚动穿透 -->
<zhibai-virtualList :disable-bounce="true" />
<!-- 启用弹性效果(默认) -->
<zhibai-virtualList :disable-bounce="false" />
说明:
bounces属性只控制橡皮筋效果,不影响滚动穿透- 当列表滚动到顶部或底部时,继续滚动会自动穿透到外层页面
- 这是使用 scroll-view 原生属性实现的,兼容性最好
平台支持:
- ✅ 微信小程序:完全支持
- ✅ APP:完全支持
- ⚠️ H5:部分支持(取决于浏览器)
License
MIT

收藏人数:
下载插件并导入HBuilderX
下载示例项目ZIP
赞赏(0)
下载 174
赞赏 0
下载 11675492
赞赏 1897
赞赏
京公网安备:11010802035340号