uni-app 中获取页面滚动高度应优先使用 onPageScroll 生命周期函数,取 e.scrollTop;若不可用则降级为 scroll-view 的 @scroll 事件并取 e.detail.scrollTop,注意三端兼容与性能优化。

uni-app 里想拿到页面滚动高度,别碰 window.pageYOffset 或 document.documentElement.scrollTop —— 这俩在小程序和 App 端直接报 undefined,H5 虽能跑但跨端一打包就废。
onPageScroll 是唯一可靠的页面级滚动监听入口
它不是事件,是页面生命周期函数,只在页面根容器可滚动时触发(比如内容超一屏、page.json 没设 "disableScroll": true)。参数 e 是个对象,只有 e.scrollTop 和 e.scrollLeft 两个字段,单位 px,恒为正。
- 微信小程序、App、H5 都支持;支付宝小程序不支持,得降级处理(比如用
scroll-view包一层) - 必须写在页面级 Vue 实例上,组件里定义无效
-
onPageScroll不会因scroll-view滚动而触发 —— 它只管“整个页面”的滚动 - 如果页面用了原生导航栏(
"navigationStyle": "custom"),且没手动加scroll-view,那滚动容器就是页面根节点,onPageScroll才起作用
scroll-view 的 @scroll 事件只管自己内部滚动
当你把内容包进 <scroll-view scroll-y></scroll-view>,页面级滚动就消失了,此时 onPageScroll 彻底失灵。必须改用 @scroll 监听,取值方式也不同:不是 e.scrollTop,而是 e.detail.scrollTop。
-
@scroll触发频率高,建议加节流(比如setTimeout+ 标志位),避免频繁赋值data导致渲染卡顿 - 不能依赖
e.detail.scrollHeight判断是否到底部 —— 小程序端这个值常不准,得用uni.createSelectorQuery()查容器真实scrollHeight,再比对 - 若同时存在多个
scroll-view,每个都要单独绑定@scroll,不能共用一个 handler - H5 下
scroll-view会生成两层 wrapper,e.detail的值可能滞后一帧,首次进入需主动调一次scrollIntoView或scrollTo同步状态
三端统一获取滚动高度的最小可行方案
没有“一套代码通吃”的银弹,但可以按优先级 fallback:
- 先尝试注册
onPageScroll,拿到e.scrollTop就直接用 - 若当前页面禁用了原生滚动(如自定义下拉刷新、固定头部),或运行在支付宝小程序,则降级到
scroll-view+@scroll - 避免在
onPageScroll里调uni.createSelectorQuery()—— 小程序端同步查询会阻塞滚动帧,H5 下也可能触发 layout thrashing - 需要存滚动位置做恢复(比如 tab 切换后回滚)时,不要只存
scrollTop,还得记当前是走onPageScroll还是scroll-view路径,否则 restore 时可能错配
最易被忽略的一点:页面样式里写了 overflow: hidden 或父容器高度撑不满,onPageScroll 就永远不会触发 —— 它不看逻辑,只看浏览器/小程序引擎是否真产生了滚动行为。


















