onPageScroll是唯一可靠方式,因其专用于监听页面级滚动距离scrollTop,支持App、微信小程序和H5端,而@scroll仅作用于scroll-view组件内滚动,无法获取整个页面的滚动值。

页面滚动距离只能用 onPageScroll 拿,不是 @scroll,也不是 scroll-view 的事件。 否则你永远拿不到整个页面的 scrollTop。
为什么 onPageScroll 是唯一可靠方式
uni-app 的「页面滚动」指整个页面容器(<page></page> 级)的滚动,和 DOM 中 window.scrollY 对应。只有 onPageScroll 生命周期能稳定捕获这个值,它在 App、微信小程序、H5 均可用;支付宝小程序不支持,这点必须提前确认。
常见错误现象:
- 给
<scroll-view></scroll-view>加@scroll,但页面本身没用scroll-view包裹全部内容 → 滚动时@scroll根本不触发 - 在
mounted里用uni.createSelectorQuery()查元素位置,却忘了onPageScroll的参数e.scrollTop才是实时滚动距离 - 误以为
onReachBottom能替代onPageScroll→ 它只在触底时触发一次,无法获取中间过程值
onPageScroll 的参数和典型用法
它接收一个对象 e,结构固定:{ scrollTop: number, scrollLeft?: number }。其中 scrollTop 单位为 px,恒为非负整数,从页面顶部开始累加。
使用场景示例:
- 吸顶导航:当
e.scrollTop >= this.headerHeight时显示固定栏 - 悬浮按钮:判断是否已滚过某个元素,如
e.scrollTop >= this.targetTop - 滚动进度条:计算
Math.min(100, Math.round((e.scrollTop / (this.pageHeight - window.innerHeight)) * 100))
注意:onPageScroll 在 H5 上会高频触发,建议加防抖(比如 setTimeout + clearTimeout),避免频繁 setState 或计算影响性能。
如何获取某个元素距离页面顶部的静态位置
滚动监听归监听,元素定位归定位 —— 二者不能混用。要拿到某元素(比如 <view id="anchor"></view>)初始时离页面顶部多远,必须用 uni.createSelectorQuery(),且需确保节点已渲染完成。
关键点:
- 必须在
onReady或onShow后调用,不能在data初始化阶段就查(节点未挂载) - 必须加
.in(this),否则查询上下文不对,返回null - 返回的
data.top是元素上边界到视口顶部的距离,不是到页面顶部;若页面已滚动,需叠加当前scrollTop才得绝对位置
简短示例:
onReady() {
const query = uni.createSelectorQuery().in(this);
query.select('#anchor').boundingClientRect(res => {
if (res) {
this.anchorTop = res.top + this.scrollTop; // 注意:this.scrollTop 来自 onPageScroll 最近一次缓存
}
}).exec();
}容易被忽略的兼容性与样式陷阱
onPageScroll 不是“有页面就一定触发”。它依赖页面根容器具备可滚动能力,而这个能力极易被 CSS 破坏:
-
<page></page>或其直接子容器设了overflow: hidden→ 滚动被禁,onPageScroll永远不执行 - 内容高度不足一屏 → 没有滚动条,自然不会触发
- 在某些 Android App 端,如果页面用了
fixed布局且未正确设置height: 100vh,可能导致滚动区域错位 - H5 端若启用了
enablePullDownRefresh: true,下拉刷新期间scrollTop可能为负值(极少数版本),需做Math.max(0, e.scrollTop)容错
最稳妥的做法:先确认页面能手动滚动,再检查控制台是否打印 onPageScroll 日志;如果没反应,优先排查样式和内容高度,而不是改逻辑。


















