uni-app中下拉刷新与上拉加载需结合长列表优化:分平台配置onreachbottomdistance(小程序建议150、h5用scroll-view)、显式开启enablepulldownrefresh;避免直接赋值list,下拉用$nexttick清空、上拉用push扩展,并重置分页参数。

uni-app 里下拉刷新和上拉加载本身不难,难的是把它们和长列表优化真正串起来——单独配 enablePullDownRefresh 或写个 onReachBottom,列表一过百条就卡;不控制渲染范围、不设缓冲区、图片没懒加载,再好的刷新逻辑也救不了滚动掉帧。
页面配置必须分平台设 onReachBottomDistance 和 enablePullDownRefresh
小程序和 App 对滚动触底距离的感知差异极大,H5 更是完全依赖 JS 滚动监听。硬写死 onReachBottomDistance: 100 在 iOS 微信里大概率失效(实际触发位置偏移 200px+),导致“明明滑到底了却不加载”。
- pages.json 中对应页面的
style节点下,onReachBottomDistance建议设为150(小程序端较稳),H5 端需额外用scroll-view+scrolltolower替代 -
enablePullDownRefresh必须在 pages.json 里显式开启,仅靠 JS 中定义onPullDownRefresh函数无效 - App 端若用 nvue,
onReachBottom不触发——得改用scroll-view的scrolltolower事件
onPullDownRefresh 和 onReachBottom 里不能直接 this.list = [] 或 this.list.push()
直接赋值会触发全量响应式追踪,尤其当 list 是几百个对象组成的数组时,Vue 代理开销爆炸;更糟的是,如果列表用了虚拟滚动,这种操作会让 offsetTop 计算错位,出现白屏或重复渲染。
- 下拉刷新时:先清空数据前,用
this.$nextTick(() => { this.list = []; })包一层,避免 setData 冲突 - 上拉加载时:别用
this.list = [...this.list, ...newData],改用this.list.push(...newData)(减少响应式对象重建) - 两者都必须重置分页参数:
this.pageNum = 1(下拉)或this.pageNum++(上拉),且要校验newData.length 来判断是否到底
scroll-view 实现虚拟滚动时,scrollTop 计算必须用固定行高
uni-app 没有 DOM layout 测量 API 可靠支持动态高度项,uni.createSelectorQuery() 在真机上测高误差大、异步延迟高,会导致可视区域索引跳变、列表闪动甚至错位。
- 所有列表项必须设固定高度(如
height: 120rpx),禁用min-height、flex: 1或文字换行撑高 - 起始索引严格用
Math.floor(scrollTop / 120),缓冲区建议上下各 3–5 条(总渲染数 ≤ 11),太少会白屏,太多失去优化意义 - 容器高度必须写死:
style="height: 600rpx",且scroll-y为 true,否则 iOS 微信里scrollTop始终为 0 - 别在
scroll回调里频繁 setData,加防抖(setTimeout+ 清除机制)或节流(每 16ms 最多更新一次)
图片懒加载和尺寸控制比刷新逻辑更容易被忽略
90% 的“刷新后卡顿”其实不是逻辑问题,而是图片解码阻塞主线程:未设 lazy-load 的 image 组件,在 scroll-view 滚动时会批量触发加载,iOS 小程序直接 CPU 拉满;更隐蔽的是,没设宽高的图片会让 uni-app 等加载完成才布局,引发 layout thrashing。
- 所有列表中
image必须加lazy-load属性(小程序/APP 有效,H5 无视) - 显式设置
width和height,或用mode="aspectFill"+ 容器overflow: hidden - 禁止用
background-image渲染列表图——小程序不支持背景图懒加载,且无法控制解码时机 - 服务端返回图片 URL 时,务必带尺寸参数(如
?width=300&height=200),前端不做 runtime resize
真正卡住长列表的,从来不是“怎么写刷新”,而是“渲染多少”“图片何时解码”“高度怎么算”这三件事没对齐。一旦开始手动实现虚拟滚动,就别再幻想靠框架自动管理可视区域——你得自己守着行高、缓冲区、setData 频率这三道线。











