onPageScroll需配合navigationStyle: custom才能生效,否则原生导航栏会拦截滚动事件;需手动实现导航栏并节流处理,防负值、设渐变区间、仅调背景alpha通道以避免iOS文字发虚。

onPageScroll 必须配合 navigationStyle: custom 才能触发
很多人写了 onPageScroll 却完全没反应,根本原因是 pages.json 里没关原生导航栏。uni-app 的滚动监听只在自定义导航栏页面生效,否则系统直接走原生滚动逻辑,onPageScroll 就是摆设。
必须在对应页面的 pages.json 中显式配置:
"navigationStyle": "custom"
不加这句,iOS 和安卓真机上都收不到 scrollTop;H5 端即使能触发,样式也会和原生栏打架。
- 加了之后,页面顶部区域变成空白,你得自己用
<view>手写导航栏 - 别试图保留原生栏再叠一层——会遮挡、错位、状态栏文字色失控
- 如果用了
<scroll-view>包裹整个页面,onPageScroll也会失效,因为滚动被组件劫持了
scrollTop 映射 alpha 值要防负值、设区间、做截断
iOS 下拉刷新时,onPageScroll 第一次返回的 scrollTop 可能是 -45 这种负数,直接除会导致 alpha 为负,背景变黑或发虚。不能写 scrollTop / 100 就完事。
正确做法是三步走:
- 用
Math.max(0, e.scrollTop)把负值归零 - 设定一个渐变区间,比如
fadeRange = 120(从 0 滚到 120px 完成全透→全不透) - 用
Math.min(1, maxedScroll / fadeRange)得到稳定 0~1 的系数
示例代码片段:
onPageScroll(e) {<br> const scrollTop = Math.max(0, e.scrollTop);<br> const fadeRange = 120;<br> const alpha = Math.min(1, scrollTop / fadeRange);<br> this.navBgAlpha = alpha;<br>}
别用 scrollTop > 100 ? 1 : 0.5 这类硬切逻辑——那是突变,不是渐变。
背景色渐变不能只靠 opacity,尤其 iOS 上文字会发虚
对整个导航栏容器设 opacity 是最常见也最坑的做法:iOS 上文字边缘模糊、图标变灰、阴影失真,而且无法单独控制文字颜色反差。
真正可控的方式是只动背景色的 alpha 通道:
- 用
rgba(255, 255, 255, {{navBgAlpha}})绑定background-color - 文字颜色另起变量,比如滚过 80px 后从白色切到深灰:
titleColor: navBgAlpha > 0.6 ? '#333' : '#fff' - 如果要带背景图,别叠加 opacity,改用
background-image+background-color: rgba(...)双层混合
注意:微信小程序里 uni.setNavigationBarColor 不支持透明度,所以这条路只适用于自定义导航栏场景。
节流不处理,低端机一滑就卡顿
onPageScroll 在安卓中可能每 16ms 触发一次,频繁更新响应式数据会让 Vue 或小程序 setData 压力爆炸,低端机直接掉帧、文字跳动、导航栏闪烁。
必须加节流,且不要在回调里直接赋值:
- 用
setTimeout缓存最后一次滚动值,延迟 16ms 再更新(比防抖更稳) - 避免每次调用
this.$forceUpdate()或this.setData() - 把计算逻辑抽离,比如
computeNavStyle(scrollTop)返回对象,再一次性合并赋值
容易被忽略的一点:H5 端如果容器没设固定高度或 overflow: auto,onPageScroll 可能压根不触发——它依赖的是 document.documentElement.scrollTop,不是元素滚动。


















