lazy-load 在 scroll-view 中不可靠,因微信小程序仅支持页面级滚动监听;需手写 uni.createintersectionobserver 并严格遵循三步:onready 后创建、observe 真实 ref 节点、正确配置 threshold 数组,否则白屏或内存泄漏。

直接用 lazy-load 属性在多数真实场景下不可靠,尤其在 scroll-view 里完全失效;真要稳定加载,必须手写 uni.createIntersectionObserver,否则安卓卡、小程序不触发、H5 无响应。
为什么 lazy-load 在 scroll-view 里不工作
微信小程序规范明确限制:该属性只监听页面级滚动(onPageScroll),而 scroll-view 是自定义滚动容器,不走原生滚动路径。这不是 bug,是平台设计如此。
- 现象:
<scroll-view scroll-y="true"><image :src="url" lazy-load></image></scroll-view>滑动时所有图片仍一次性请求,或始终空白 - H5 端默认不生效,需额外配置(如
decode="async"),且行为不一致 - 无法控制预加载距离(比如提前 200px 加载),也无法感知是否真正进入可视区
手写 uni.createIntersectionObserver 的关键三步
不是调个 API 就完事,漏掉任一环节都会白屏、重复加载或静默失败。
- 必须在
onReady或mounted后创建观察器——created或data里执行会因 DOM 未挂载导致this.$refs为空 - 观察目标必须是真实节点:
observer.observe(this.$refs.imgRef),不能传字符串选择器(如'#img-1')指望自动查找 -
threshold参数跨端不兼容:微信小程序只认数组(如[0, 0.1, 0.5]),设成数字(如0.2)会静默失败;H5 才支持单数值 - 每次
observe()后记得调用observer.disconnect(),否则内存泄漏
图片高度不确定?布局抖动就不可避免
瀑布流、列表页里图片宽高比各异,不预设高度会导致 DOM 渲染后重排,滚动时“跳动”,甚至触发重复加载。
- 最优解:服务端返回图片宽高字段,前端直接设
style="{ height: item.height + 'px' }" - 做不到就用
uni.getImageInfo预加载——它返回真实尺寸,比new Image()可靠得多(后者在安卓 WebView 里不触发解码) - 绝对不要用
v-if控制图片显隐,组件销毁重建会重新赋值src,又触发一遍加载;改用:style="{ opacity: loaded ? 1 : 0 }"+ CSS transition - 如果用 uView 的
u-lazy-load,注意:img-mode不是widthFix时,height必须设为固定值(如300rpx),auto或100%会导致图片不显示
安卓图片加载慢,懒加载反而更卡?
根本原因不是网络,是安卓 WebView 下 <image></image> 默认走 JS + Canvas 模拟渲染,解码、缩放、绘制全在主线程,低端机上极易卡死。
- 优先启用 nvue 页面 + 原生渲染:在
manifest.json中设"nvueStyle": true,并确保页面后缀是.nvue - 预加载关键图必须用
uni.preloadImage,别用new Image()——前者触发原生层预解码,后者只是下载完扔进缓存队列 - 慎用
mode="aspectFill"或scaleToFill,这些模式需 CPU 裁剪,安卓下无硬件加速支持 - CDN 动态裁剪优先:URL 加参数如
?x-oss-process=image/resize,w_200/format,webp,把原图压到几 KB 再懒加载
最易被忽略的点:scroll-view 必须设固定高度 + scroll-y="true",否则连滚动区域都不存在;还有,enable-back-to-top 会劫持滚动事件,导致 bindscroll 失效——这些硬条件不满足,连 IntersectionObserver 都没机会起作用。











