uni-app 瀑布流必须用 js 动态分组+多列 flex-column 实现,因三端对 column-count/grid 支持差:小程序忽略、安卓降级、h5 不重排;需服务端宽高比、预设高度、节流更新与 scroll-view 固定高度配置。
uni-app 不支持真正的 css 瀑布流(column-count、display: grid 或 flex-direction: column; flex-wrap: wrap),三端渲染不一致,真机上必然错位、留白、滚动失效。能跨平台稳定跑的,只有 js 动态分组 + 多列 flex-direction: column 布局。
为什么不能用 CSS column-count 或 grid 实现瀑布流
小程序(尤其微信)直接忽略 column-count;display: grid 在部分安卓小程序中降级为普通流式布局;H5 虽能显示,但图片加载后高度变化不会触发重排,导致底部留白、触底监听失效。这不是写法问题,是底层引擎限制。
- 在
scroll-view里写column-count: 2,等于没写 -
grid-template-columns: repeat(2, 1fr)+grid-auto-flow: dense在 H5 可见,但无法联动图片真实高度更新 - 服务端返回宽高比(如
aspectRatio: "4:3")比前端 JS 估算更稳,能减少首屏闪动
JS 动态分组:两列/三列怎么分才不卡
核心是把图片数组按“当前最短列”原则分配,而不是简单取模。取模(idx % colCount)会导致列高严重不均,视觉上就是“假瀑布流”。
- 维护一个列高数组:
columnHeights = [0, 0](两列)或[0, 0, 0](三列) - 每张图加载完成(
@load触发)后,拿到真实高度,找Math.min(...columnHeights)对应索引,push进该列,并更新该列高度 - 分发逻辑必须在
computed或watch中完成二维数组构建(如columns = [[], []]),不能在v-for模板里实时计算 - 列数动态算:
const colCount = Math.min(3, Math.floor(uni.getSystemInfoSync().windowWidth / 150)),150rpx 是单图最小宽度估算值
图片加载前高度塌陷怎么破
图片未加载时 height 为 0,列容器塌缩,后续插入全部错位。这不是样式问题,是生命周期时机问题。
- 服务端必须返回
width和height字段,前端用width: 100%+height: calc(100% * item.height / item.width)预设内联样式 - 若无服务端配合,用
uni.getImageInfo({ src })并发 ≤ 3 预加载,拿到尺寸后再插入对应列,比@load后查 DOM 快得多 - 每张图的父
view必须设min-height: 200rpx(或更高),防止初始渲染空白 - 高度修正必须节流:同一列多次更新需防抖,避免频繁
this.$forceUpdate()或setData
scroll-view 布局和滚动监听的硬坑
很多人以为加个 scrolltolower 就能懒加载,结果 iOS 微信里滚到底部根本不触发,或者只触发一次——问题不在事件名,而在容器配置。
-
scroll-view必须显式设scroll-y="true",且父容器有**固定高度**(如height: calc(100vh - 100rpx)),小程序不识别vh单位 - 禁用
position: absolute,iOS 微信中会导致滚动事件丢失;改用transform: translateY()模拟定位更稳 - 子项不能是带异步加载的自定义组件(如封装好的
WaterfallItem),父组件无法感知子项高度变化,必然底部留白 - 安卓真机上
setData大量节点易卡顿,建议用uni.createSelectorQuery()手动查高度做增量更新,而非全量重绘整个columns
真正难的不是写分组逻辑,而是让每张图在加载前后都保持列容器高度连续、不跳动。预估高度要准,真实高度要快,更新要节流,列数要响应式——漏掉任一环,瀑布流就在真机上“流”歪了。











