uni-app 瀑布流不能用 column-count 或 grid 是因三端渲染不一致:小程序忽略 column-count、grid 在安卓降级,H5 无法联动懒加载;须用 JS 动态分配图片至最短列并精准控制加载与更新时机。

uni-app 里为什么不能用 column-count 或 display: grid 做瀑布流
因为小程序端(微信、支付宝等)会直接忽略 column-count,display: grid 在部分安卓小程序中降级为普通流式布局,H5 虽能跑通但无法响应滚动懒加载。真实项目中只要一上真机,就会出现列错位、图片堆叠、触底失效等问题。
根本原因不是写法错,而是三端渲染引擎对 CSS 瀑布流的支持不一致:微信小程序用 WebView 渲染但禁用多列分栏逻辑;App 端 nvue 模式下连 flex-direction: column 都受限;H5 虽支持但滚动监听和图片高度动态变化无法联动。
- 别在
scroll-view里套column-count—— 小程序里它等于没写 - 别依赖
grid-template-columns: repeat(2, 1fr)+grid-auto-flow: dense—— H5 可见,但图片加载后高度变化不会触发重排,导致底部留白 - 服务端返回宽高比(如
aspectRatio: "4:3")比前端 JS 算更稳,避免首屏闪动
怎么用 JS 动态分配图片到最短列(核心逻辑)
维护一个 columnHeights 数组,长度等于列数,初始全为 0;每张图加载完成拿到真实高度后,找数组里最小值的索引,把这张图 push 进对应列的数据数组,并更新该列高度。
关键点不在“怎么分”,而在“什么时候分”:不能等所有图片 @load 完再统一分配,得边加载边插入,否则首屏白屏或卡顿。
- 预设占位高度(如
200rpx)+ 服务端返回宽高比,先让列有初始高度,避免 layout shift - 图片
@load回调里调用this.updateColumn(item, height),而不是存起来批量处理 - 用
Math.min(...columnHeights)找最小列,但注意 Safari 对展开运算符处理慢,数据量大时改用循环遍历 - 列数要响应式:用
uni.getSystemInfoSync().screenWidth判断,比如,<code>375–750px → 2列,> 750px → 3列
scroll-view 布局和滚动监听的几个硬坑
很多人以为只要给 scroll-view 加个 scrolltolower 就能懒加载,结果 iOS 微信里滚到底部根本不触发,或者只触发一次。
问题根源是:子元素用了 position: absolute、父容器没设明确高度、或高度用了 100vh(小程序不识别 vh 单位)。
- 必须用
height: calc(100vh - 100rpx)这类动态计算,减掉导航栏、TabBar 等固定区域高度 - 绝对定位(
position: absolute)在scroll-view内会导致滚动事件丢失,尤其 iOS 微信;改用transform: translateY()模拟偏移更可靠 -
onReachBottom在页面级可用,但在自定义组件内需透传,且不能和scroll-view的scrolltolower混用,否则冲突 - 安卓真机 setData 大量节点易卡顿,建议用
uni.createSelectorQuery()手动查最后一项位置判断是否接近底部,而非全量更新
图片加载完成后的高度重算与视图更新
图片加载完的真实高度,不能靠 CSS 自动撑开——image 标签默认不占位,父容器高度为 0,会导致列高数组完全不准。
必须主动获取并更新:要么服务端返回精确 height(单位 rpx),要么前端用 uni.getImageInfo 预加载,或在 @load 后用 createSelectorQuery 查节点高度。
-
uni.getImageInfo是最准的,但增加请求耗时;适合关键首屏图,非全量使用 -
@load里直接取event.detail.height不可靠(H5 返回 px,小程序返回 rpx,nvue 不返回),统一走 query 更稳 - 查高度必须加
this.$nextTick()(vue2)或await nextTick()(vue3),否则 DOM 还没渲染完,query 返回height: 0 - 更新列高后,不要直接
this.columns = [...]全量重赋值,用this.$set(this.columns[i], index, newItem)或 splice 做增量更新,减少 diff 开销
实际最难的不是算法,是把「图片加载时机」「节点查询时机」「setData 频率」「跨端单位转换」这四件事在同一个生命周期里对齐。多数翻车都发生在 iOS 微信里图片加载慢 + query 没等 $nextTick + 直接全量 setData,三者叠加就彻底乱序。


















