应使用 window.scrollY,它是现代标准 API,返回视口垂直偏移量,不依赖文档结构;document.body.scrollTop 和 document.documentElement.scrollTop 在部分安卓 WebView 和旧版 UC 浏览器中常返回 0。

监听商品详情页滚动位置该用 window.scrollY 还是 scrollTop?
直接用 window.scrollY,别碰 document.body.scrollTop 或 document.documentElement.scrollTop。前者是现代标准 API,返回视口垂直偏移量,不依赖文档结构或 DOCTYPE;后两者在部分安卓 WebView、旧版 UC 浏览器里常返回 0,哪怕页面明明已滚动到底部。
注意:首次读取必须等 DOMContentLoaded 触发后,否则可能拿到 0(DOM 还没完成 layout)。
监听 scroll 事件却没触发?先查这三项硬条件
90% 的“监听不到”不是 JS 写错,而是容器根本不可滚动。必须同时满足:
- 容器有明确的
height或max-height(不能是height: auto) - 容器设置了
overflow-y: auto或overflow-y: scroll - 容器子内容总高度 > 容器自身高度(即
scrollHeight > clientHeight)
调试时打开 DevTools → Elements 面板 → 选中目标容器 → 看右侧面板 Computed 样式,确认 overflow 计算值是否为 auto/scroll,再比对 scrollHeight 和 clientHeight 数值。
立即学习“前端免费学习笔记(深入)”;
移动端 touch 滚动不触发 scroll?补监听 touchmove 并设 passive: false
某些安卓 WebView(如旧版 UC、定制浏览器)在快速拖拽时,scroll 事件会延迟甚至丢失首帧。仅靠 scroll 监听,scrollTop 可能长时间卡在初始值。
稳妥做法是双监听:
- 保留
container.addEventListener('scroll', handler)作为主通道 - 同时加
container.addEventListener('touchmove', handler, { passive: false }) - 两个回调里都读
this.scrollTop(不是event.touches[0].pageY)
passive: false 是必须的——否则 preventDefault() 会被静默忽略,Chrome 控制台还会报错 Unable to preventDefault inside passive event listener。
节流必须用 requestAnimationFrame,别手写 setTimeout
滚动事件高频触发(手指滑动时每秒可达数十次),若回调里做 DOM 查询、getBoundingClientRect() 或样式计算,立刻掉帧。
推荐用 requestAnimationFrame 节流,比 setTimeout 更稳:
- 声明一个
ticking标志位 - 在
scroll回调里只判断是否需要调度下一帧 - 实际逻辑统一放在
requestAnimationFrame回调中执行
注意:不要在回调外缓存 scrollTop 值——它只在滚动发生时实时更新,静态读取可能过期或为 0。



















