更新记录

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

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT License

Copyright (c) 2026 w-waterfall contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

暂无用户评论。