更新记录
1.0.0(2026-07-23) 下载此版本
- 新增双列瀑布流与虚拟列表功能,仅渲染可视区域及缓冲区内容
- 支持按预估高度自动分配较短列,以及左右均分模式
- 卡片采用普通 DOM 流排列,不使用绝对定位和滚动后二次高度测量
- 兼容 H5、App 和小程序
平台兼容性
uni-app(3.8.0)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| × | √ | √ | √ | √ | - | - | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| × | × | √ |
w-waterfall 双列虚拟瀑布流
适用于 uni-app Vue3 的双列瀑布流组件。虚拟模式仅渲染可视区域及缓冲区内容,卡片按普通 DOM 流排列,不使用绝对定位,也不在滚动后测量卡片高度。
特性
- 支持 H5、App 和微信小程序
- 支持预估高度虚拟列表
- 支持自动选择较短列和左右均分
- 支持页面滚动
- 微信小程序使用普通具名插槽,避免循环 scoped slot 导致重复插槽和滚动闪烁
- 无第三方依赖
安装
将插件导入项目后,组件位于:
uni_modules/w-waterfall/components/w-waterfall/w-waterfall.vue
目录符合 easycom 规范,页面中可以直接使用 <w-waterfall>。
基本用法
<template>
<view class="page">
<w-waterfall
ref="waterfallRef"
:list="goodsList"
:item-height-field="getEstimatedItemHeight"
key-field="goods.id"
:column-gap="16"
:row-gap="16"
@window-change="handleWindowChange"
>
<template #left>
<view
v-for="entry in leftEntries"
:key="entry.key"
:style="entry.style"
>
<goods-card :item="entry.item" />
</view>
</template>
<template #right>
<view
v-for="entry in rightEntries"
:key="entry.key"
:style="entry.style"
>
<goods-card :item="entry.item" />
</view>
</template>
</w-waterfall>
</view>
</template>
<script setup lang="ts">
import { onPageScroll } from '@dcloudio/uni-app'
import { ref } from 'vue'
interface GoodsItem {
goods: { id: number }
imageHeight: number
title: string
}
interface WaterfallEntry {
item: GoodsItem
index: number
key: string | number
style?: Record<string, unknown>
}
const titleHeight = 80
const goodsList = ref<GoodsItem[]>([])
const waterfallRef = ref<{ setScrollTop: (value: number) => void } | null>(null)
const leftEntries = ref<WaterfallEntry[]>([])
const rightEntries = ref<WaterfallEntry[]>([])
// 返回卡片内容的完整预估高度,单位 px,不包含 rowGap。
const getEstimatedItemHeight = (item: GoodsItem) => {
return item.imageHeight + uni.upx2px(titleHeight)
}
const handleWindowChange = (window: {
left: WaterfallEntry[]
right: WaterfallEntry[]
}) => {
leftEntries.value = window.left
rightEntries.value = window.right
}
onPageScroll((event) => {
waterfallRef.value?.setScrollTop(event.scrollTop || 0)
})
</script>
goods-card 是业务卡片示例,不包含在插件中,请替换为项目自己的卡片组件。
高度预估
虚拟列表不进行后续 DOM 高度测量,因此 itemHeightField 返回值应与卡片实际内容高度一致:
const getEstimatedItemHeight = (item: GoodsItem) => {
return item.imageHeight + uni.upx2px(titleHeight)
}
- 返回值单位为
px - 返回值不包含
rowGap,行间距由组件自动加入 - 未传入函数或返回值无效时,使用
estimatedItemHeight,默认320rpx - 标题、图片或其他区域高度发生变化时,应同步调整使用层计算函数
- 如果标题使用最小高度且内容可能继续撑高,预估值会产生累计偏差;虚拟模式建议固定卡片内容高度
微信小程序注意事项
微信小程序使用页面滚动时,必须通过页面的 onPageScroll 通知组件:
onPageScroll((event) => {
waterfallRef.value?.setScrollTop(event.scrollTop || 0)
})
如果省略,组件会一直认为页面位于顶部,滚动到后续区域时可能没有可渲染内容。
每个渲染项必须绑定组件返回的 entry.style,它负责行间距及虚拟占位:
<view v-for="entry in leftEntries" :key="entry.key" :style="entry.style">
<!-- 业务卡片 -->
</view>
不要把同一个 scoped slot 放到组件内部循环调用。uni-app 小程序端对循环同名 slot 的表现不一致,本组件通过 window-change 和两个普通具名 slot 避免该问题。
Props
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| list | Array | 必填 | 数据源 |
| keyField | string | Function | id |
唯一字段,字符串支持 goods.id 形式的点号路径 |
| itemHeightField | Function | - | 卡片内容高度计算函数,返回 px |
| columnGap | number | 16 |
列间距,单位 rpx |
| rowGap | number | 16 |
行间距,单位 rpx |
| padding | number | 0 |
组件左右内边距,单位 rpx |
| mode | auto | split |
auto |
auto 选择预估更短列;split 按左右数量分发 |
| delay | number | 0 |
非虚拟 auto 模式逐项分发间隔,单位 ms |
| virtual | boolean | true |
是否启用虚拟列表 |
| estimatedItemHeight | number | 320 |
高度函数无效时的兜底高度,单位 rpx |
| overscan | number | 600 |
可视区域上下额外缓冲,单位 rpx;内部至少保留约两个视口 |
| viewportHeight | number | 系统窗口高度 | 可视区域高度,单位 px |
| scrollTop | number | 0 |
页面滚动距离,单位 px;微信小程序推荐使用 setScrollTop() |
Events
| 事件 | 参数 | 说明 |
|---|---|---|
| window-change | { left, right } |
当前需要渲染的左右列数据 |
| layout-done | - | 当前数据完成分列 |
每个渲染项包含:
interface WaterfallEntry<T> {
item: T
index: number
key: string | number
style?: Record<string, unknown>
}
Slots
| 名称 | 说明 |
|---|---|
| left | 左列普通具名插槽 |
| right | 右列普通具名插槽 |
Expose
| 方法 | 说明 |
|---|---|
| setScrollTop(scrollTop) | 更新页面滚动位置 |
| reflow() | 按当前数据和预估高度重新分列 |
隐私与权限
- 不包含广告
- 不采集或上传任何数据
- 不申请系统权限
许可协议
MIT

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