uni-app 页面滚动监听必须使用 onPageScroll 生命周期钩子,而非 scroll-view 的 @scroll 事件;其参数为 { scrollTop }(单位 px,恒为正),在 App、微信小程序、H5 可用,但支付宝小程序不支持,且受页面根容器可滚动性及样式(如 overflow: hidden)影响。

uni-app 页面滚动监听用 onPageScroll,不是 scroll-view 的事件
很多人一上来就给 scroll-view 加 @scroll,结果发现页面整体滚动(比如下拉刷新、长列表滚动)根本触发不了——因为那是组件内滚动,而「页面滚动距离」通常指整个页面的 scrollTop,必须用生命周期钩子。
uni-app 的页面级滚动监听只靠 onPageScroll,它在 App、微信小程序、H5 都可用,但注意:支付宝小程序不支持,且仅在页面根容器可滚动时才触发(比如内容超出一屏)。
-
onPageScroll参数是{ scrollTop },单位为 px,值为正整数,不会为负 - 它在滚动中高频触发,别在里面直接调
this.setData或执行重操作,容易卡顿 - H5 端会受
body或page容器样式影响,若设置了overflow: hidden,onPageScroll就不触发
为什么 uni.createSelectorQuery() 拿不到页面滚动距离
有人想用查询 API 去读 document.scrollingElement.scrollTop,这在 H5 可行,但在小程序里根本没 document,uni.createSelectorQuery 也查不到页面根滚动容器——它只查组件节点,而页面滚动容器不属于任何组件树。
强行在小程序里模拟会导致兼容性断裂,比如:App 端返回的是 WebView 内部 scrollY,但不同平台 WebView 实现不一致;微信小程序里甚至无法访问原生滚动对象。
- 不要尝试用
uni.createSelectorQuery().selectViewport()获取滚动位置,它在多数平台返回null - 不要在
mounted或onReady里预读 scrollTop,页面还没开始滚动,这个值恒为 0 - 如果真需要初始化时的滚动位置(比如恢复上次位置),应从
onLoad参数或本地缓存读,而非实时查询
onPageScroll 在不同平台的精度和延迟差异
这个函数不是每像素触发一次。微信小程序约 16ms 一次(接近 60fps),App 端取决于 WebView 性能,H5 则依赖浏览器的 scroll 事件节流策略——这意味着快速滑动时你收到的 scrollTop 是离散的、有跳跃的。
如果你要做吸顶、视差或滚动进度条,不能假设数据连续,得自己做简单平滑处理,比如用上一次值做插值,或加个防抖判断方向。
- 快速滚动时,
scrollTop可能跳变 20–50px,尤其低端安卓机 - iOS 微信里偶尔首帧
scrollTop为 0,哪怕页面已滚动,建议忽略前 1–2 次回调 - App 端若开启
renderMode: "webview",滚动监听更稳定;用"subNVue"模式则可能失效
监听失效的三个典型配置坑
写了 onPageScroll 却没反应?大概率栽在这几个地方。
- 页面 JSON 配置里写了
"disableScroll": true—— 这个开关会彻底禁用页面滚动,onPageScroll自然不触发 - 页面根元素(
<view class="container">)设置了height: 100vh但没设overflow-y: auto,导致内容被裁剪却不滚动 - 使用了
uni-nav-bar+statusBar且未适配安全区,某些 iOS 机型下页面实际可滚动区域变小,scrollTop增长缓慢甚至卡住
最简单的验证方式:手动拖动页面,打开调试器,在 onPageScroll 里打个 console.log,看有没有输出——没有输出,先查配置和样式,别急着改逻辑。

















