更新记录

1.0.3(2026-09-02) 下载此版本

重构

1.0.2(2024-11-20) 下载此版本

  1. 优化dom问题判断

1.0.1(2024-11-18) 下载此版本

  1. 优化
属性 说明 类型 默认值 可选值
backTopShow 返回顶部 Boolean true true/false
scrollwithanimation scroll-view (scroll-with-animation) Boolean true true/false
isnextpage 是否已是最后一页 Boolean false true/false
imgSrc 列表中图片字段 String src (与列表中图片字段对应) ---
方法 说明 接收值
backTop 返回顶部 (使用ref方式调用) val (true 初始化数据)
Init 数据处理渲染(使用ref方式调用) arr (列表包含图片)
scroll 滚动事件 scrollTop (当前滚动的距离)
scrolltolower 触底事件 ---
插槽 说明 接收值
top 列表上方的内容 ---
bottom 列表下方的内容 ---
Backtotop 自定义返回顶部样式 ---
left 列表左侧循环渲染的内容 item
right 列表右侧循环渲染的内容 item
查看更多

平台兼容性

uni-app

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟

其他

多语言 暗黑模式 宽屏模式

SL-Waterfall 瀑布流组件

适用于 uni-app(H5 / 各端小程序)的瀑布流组件。支持网络图片(无需预知宽高)、多列布局、左列不低于右列、渐进渲染、触底加载、返回顶部、空状态。

特性

  • 网络图片自适应:通过 <image>@load 事件获取真实宽高,无需 uni.getImageInfo,规避 H5 跨域与小程序域名白名单问题

  • 多列布局:可配置列数、列间距、行间距

  • 左列不低于右列:分配后做批末修正,保证累计高度非递增,避免右列空白

  • 渐进渲染:已渲染的 item 永不删除,滚动时无抖动;DOM 量随用户浏览量增长,可控

  • 组件内滚动:基于 scroll-view,不依赖页面级生命周期,触底/返回顶部均由组件自身实现

  • H5 / 小程序通用:无平台特有 API 依赖

字段说明(Props)

字段 类型 默认值 说明
list Array [] 数据源数组,每项需包含图片地址字段
columnCount Number 2 列数
imageKey String 'image' 数据项中图片地址的字段名
columnGap Number 16 列间距(rpx)
rowGap Number 16 行间距(rpx)
padding Number 16 外层内边距(rpx)
leftHigher Boolean true 是否保证左列累计高度不低于右列
height String '100vh' scroll-view 高度(CSS 值,必须为确定值才能滚动)
enableVirtual Boolean true 是否启用渐进渲染(关闭则全量渲染)
virtualBuffer Number 600 渐进渲染缓冲区(px),距底部还剩这么多时提前渲染下一批
renderStep Number 6 每次渐进渲染增加的 item 数量
lowerThreshold Number 80 触底距离(px)
backTopThreshold Number 600 显示返回顶部按钮的滚动阈值(px)

事件说明(Events)

事件名 回调参数 说明
itemtap item 点击某个 item 时触发,返回该 item 数据
scrolltolower 滚动触底时触发,用于加载更多
scroll { scrollTop } 滚动时触发,返回当前滚动位置(节流 80ms)
backtopchange { show } 返回顶部按钮显隐变化时触发

方法说明(通过 ref 调用)

方法名 参数 说明
scrollToTop duration = 300 平滑滚动回顶部
this.$refs.waterfall.scrollToTop();

插槽说明(Slots)

插槽名 作用域参数 说明
item item 单个 item 底部内容(文案等),默认显示 item.title
footer scroll-view 内部底部,常用于加载状态
backtop 返回顶部按钮自定义样式,默认圆形半透明黑底 + ↑
empty 空数据状态自定义样式,默认居中"暂无数据"

示例

基础用法

<template>
  <sl-waterfall
    :list="list"
    :column-count="2"
    image-key="image"
    @itemtap="onItemTap"
    @scrolltolower="loadMore"
  />
</template>

<script>
export default {
  data() {
    return { list: [] };
  },
  methods: {
    loadMore() {
      // 追加数据到 this.list
    },
    onItemTap(item) {
      uni.showToast({ title: item.title, icon: 'none' });
    }
  }
};
</script>

完整示例(自定义插槽 + 触底加载 + 返回顶部 + 空状态)

<template>
  <view class="page">
    <sl-waterfall
      ref="waterfall"
      :list="list"
      :column-count="2"
      :column-gap="16"
      :row-gap="16"
      :padding="16"
      height="100vh"
      :enable-virtual="true"
      :lower-threshold="80"
      :back-top-threshold="600"
      image-key="image"
      @itemtap="onItemTap"
      @scrolltolower="loadMore"
    >
      <!-- 自定义 item 底部内容 -->
      <template v-slot:item="{ item }">
        <view class="card-footer">
          <text class="card-title">{{ item.title }}</text>
          <text class="card-author">{{ item.author }}</text>
        </view>
      </template>

      <!-- 自定义返回顶部按钮 -->
      <template v-slot:backtop>
        <view class="custom-backtop">
          <text>顶部</text>
        </view>
      </template>

      <!-- 自定义空数据 -->
      <template v-slot:empty>
        <view class="custom-empty">
          <text>📭 还没有内容</text>
        </view>
      </template>

      <!-- 触底加载状态 -->
      <template v-slot:footer>
        <view class="load-more">
          <text v-if="loading">加载中…</text>
          <text v-else-if="noMore">没有更多了</text>
        </view>
      </template>
    </sl-waterfall>
  </view>
</template>

<script>
export default {
  data() {
    return {
      list: [],
      page: 1,
      loading: false,
      noMore: false
    };
  },
  onLoad() {
    this.loadMore();
  },
  methods: {
    loadMore() {
      if (this.loading || this.noMore) return;
      this.loading = true;
      // 模拟请求
      const next = [];
      for (let i = 0; i < 8; i++) {
        const seed = (this.page - 1) * 8 + i + 1;
        next.push({
          image: `https://picsum.photos/seed/${seed}/400/${300 + (seed % 5) * 80}`,
          title: '标题' + seed,
          author: '作者'
        });
      }
      setTimeout(() => {
        this.list = this.list.concat(next);
        this.page++;
        this.loading = false;
      }, 300);
    },
    onItemTap(item) {
      uni.showToast({ title: item.title, icon: 'none' });
    }
  }
};
</script>

多列布局

<sl-waterfall :list="list" :column-count="3" :column-gap="12" :row-gap="12" />

关闭渐进渲染(数据量小时)

<sl-waterfall :list="list" :enable-virtual="false" />

调用返回顶部

<sl-waterfall ref="waterfall" :list="list" />

<script>
export default {
  methods: {
    backToTop() {
      this.$refs.waterfall.scrollToTop();
    }
  }
};
</script>

注意事项

  1. 小程序图片域名:网络图片需在 小程序后台 → 开发管理 → 服务器域名 加入合法域名(开发期可在开发者工具勾选「不校验合法域名」);H5 无此限制。
  2. easycom 配置:若目录结构为 components/SL-WX-Compent-Waterfall/index.vue(目录名与文件名不一致),需在 pages.json 配置自定义 easycom 规则:

    "easycom": {
     "custom": {
       "^sl-waterfall": "@/components/SL-WX-Compent-Waterfall/index.vue"
     }
    }
  3. height 必须为确定值:scroll-view 需明确高度才能滚动,如 100vh600rpx,不能用 auto
  4. 渐进渲染与虚拟列表区别:本组件用渐进渲染(已渲染永不删除),滚动时无 DOM 删除 → 无抖动,DOM 量随浏览量增长。如需固定 DOM 数量可自行改为虚拟列表方案。

隐私、权限声明

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

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

插件不采集任何数据

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

许可协议

MIT协议