调用window.scrollTo完成滚动后是否有可监听的触发事件?
window.scrollTo触发的滚动行为属于浏览器异步渲染任务,同步调用后后续JS代码会立即执行,此时浏览器还未完成滚动位置更新,因此拿到的是滚动前的初始值。下面是可实现滚动完成后执行逻辑的几种方案:
方案1:监听scroll事件判断目标位置
这是兼容性最好的方案,通过监听全局scroll事件,判断当前滚动位置到达目标值后执行后续逻辑,执行后立即移除事件监听避免重复触发:
const targetScrollY = 500 function onScrollFinish() { // 滚动完成后要执行的逻辑写在这里 alert(window.scrollY) // 此时能拿到正确的500 } window.scrollTo({ top: targetScrollY, behavior: 'smooth' // 不需要平滑滚动可以删除这个配置 }) const scrollListener = () => { // 滚动存在小数像素或微小误差,加2px的容错范围 if (Math.abs(window.scrollY - targetScrollY) < 2) { window.removeEventListener('scroll', scrollListener) // 短延时规避浏览器滚动收尾阶段的误差 setTimeout(onScrollFinish, 100) } } window.addEventListener('scroll', scrollListener)
方案2:同步滚动场景直接获取
如果不需要平滑滚动效果,仅需要瞬间跳到目标位置,直接修改window.scrollY是同步操作,执行后可以立即拿到正确值:
window.scrollY = 500 alert(window.scrollY) // 直接返回500
方案3:Promise封装复用
如果多次用到滚动完成回调,可以封装成通用的Promise方法,方便链式调用:
function scrollToY(targetY, smooth = true) { return new Promise((resolve) => { window.scrollTo({ top: targetY, behavior: smooth ? 'smooth' : 'auto' }) if (!smooth) { // 无平滑滚动时直接返回 return resolve() } const listener = () => { if (Math.abs(window.scrollY - targetY) < 2) { window.removeEventListener('scroll', listener) setTimeout(resolve, 100) } } window.addEventListener('scroll', listener) }) } // 使用示例 scrollToY(500).then(() => { alert(window.scrollY) })
注意:如果页面整体高度不足,无法滚动到目标位置,上述监听会一直存在,建议根据滚动距离加上3~5秒的兜底超时,超时后强制移除监听并执行回调或抛出异常,避免内存泄漏。
内容的提问来源于stack exchange,提问作者GNETO DOMINIQUE
相关产品推荐
相关产品推荐

