onPageScroll 是唯一稳定获取页面滚动距离的方式,必须写在 pages.json 注册的页面实例中,组件内无效;真机安卓有节流,参数仅含 e.scrollTop/e.scrollLeft(px,正整数);禁用滚动或内容未溢出时不会触发;H5 受 body 样式影响,使用 scroll-view 后需改用 @scroll 事件;跨端避免 window.pageYOffset 等非标准 API;支付宝小程序需降级为 scroll-view + @scroll。

onPageScroll 是唯一能稳定拿到页面级滚动距离的方式,其他写法在小程序或 App 端大概率失效。
onPageScroll 必须写在页面实例里,组件中定义无效
它不是普通事件,而是页面生命周期函数,只在 pages.json 注册的页面 Vue 实例中生效。组件里写 onPageScroll 完全不会触发。
- 真机调试时,安卓端有节流(约 16ms~60ms 一次),别依赖高频精确值
- 参数只有
e.scrollTop和e.scrollLeft,单位 px,恒为正整数 - 若页面设了
"disableScroll": true或内容没超出一屏,onPageScroll根本不触发 - H5 端受
body样式影响:比如overflow: hidden或默认margin会导致回调不执行或值不准
用了 <scroll-view scroll-y>,onPageScroll 就彻底失灵
一旦把内容包进 <scroll-view scroll-y>,页面根容器就不再滚动,onPageScroll 失去监听对象。
- 此时必须改用
@scroll事件,取值是e.detail.scrollTop,不是e.scrollTop - 需给
<scroll-view ref="myScrollView">加ref,否则无法调用scrollTo - 多个
<scroll-view>同时设scroll-y,容易互相劫持滚动事件,建议只保留一个可滚动区域 - H5 下
scroll-view会生成两层 wrapper,e.detail.scrollTop可能滞后一帧,首次进入建议手动同步一次
别碰 window.pageYOffset 和 document.documentElement.scrollTop
这两个在小程序和 App 端直接报 undefined,H5 虽能跑,但打包成小程序后立刻失效,属于跨端雷区。
-
uni.createSelectorQuery().selectViewport()在多数平台返回null,因为页面滚动容器不属于组件树 - 在
mounted或onReady里查scrollTop,值恒为 0 —— 页面还没开始滚动 - 需要恢复上次滚动位置?从
onLoad参数或本地缓存读,而不是实时查询
支付宝小程序不支持 onPageScroll,得降级处理
它没有页面级滚动监听能力,只能靠 <scroll-view> 包一层,再用 @scroll 监听。
- 降级时注意:要同时记录当前滚动路径来源(是
onPageScroll还是@scroll),否则恢复位置时可能调错 API - 判断是否到底部不能只看
e.detail.scrollHeight—— 微信小程序里这个值常不准,得用boundingClientRect查真实高度再比对 - 高频触发的滚动回调里,避免直接赋值
data或调this.$forceUpdate(),建议加节流(如每 100ms 取一次)
最易被忽略的是混用场景:同一个页面里既开了原生页面滚动,又嵌了 <scroll-view scroll-y>,这时候 onPageScroll 和 @scroll 的触发逻辑互斥,且恢复滚动位置时若没区分来源,uni.pageScrollTo 和 scrollTo 极易调错目标。


















