Scroll Snap鼠标端正常,触屏端滑动时JS滚动异常求助
触屏设备Scroll Snap滚动延迟问题修复方案
核心问题分析
- 触摸事件默认行为冲突:
pointerup中调用e.preventDefault()会干扰浏览器原生触摸滚动/Scroll Snap逻辑,导致手动触发的scrollTo和原生滚动行为冲突,首次滚动被打断。 - 滚动位置判断精度不足:
window.pageYOffset === posY的严格相等判断在触屏设备上容易失效——原生滚动可能产生小数偏移量(如100.5),和目标整数位置不匹配,触发2秒超时重试。 - 滚动事件监听逻辑缺陷:未处理滚动中途停止、动画未完全结束的边界情况,导致事件残留或判断失效。
具体修复步骤
1. 移除pointerup中的阻止默认行为代码
触屏设备上,阻止pointerup默认行为会破坏原生滚动流程,和手动scrollTo产生冲突,直接删除该行:
document.addEventListener('pointerup', (e) => { // 移除此行:e.preventDefault(); endingPosition = e.pageY; // 其余代码保留 });
2. 修正滚动位置的容差判断
将严格相等改为允许微小偏移的判断,避免精度问题触发超时:
async function smoothScroll(posY) { ignoreNextScrollEvent = true; window.scrollTo({ top: posY, behavior: 'smooth', }); try { const response = await new Promise((resolve, reject) => { const failed = setTimeout(() => { reject(); }, 2000); const scrollHandler = () => { // 允许±1px的偏移误差 if (Math.abs(window.pageYOffset - posY) <= 1) { window.removeEventListener('scroll', scrollHandler); clearTimeout(failed); resolve(); } }; // 初始检查同样用容差判断 if (Math.abs(window.pageYOffset - posY) <= 1) { clearTimeout(failed); resolve(); } else { window.addEventListener('scroll', scrollHandler, { passive: true }); } }); } catch (e) { smoothScroll(posY); } }
3. 优化滚动监听精度
用requestAnimationFrame提升滚动位置判断的准确性,确保在浏览器重绘周期内检查:
// 替换smoothScroll中的scrollHandler const scrollHandler = () => { requestAnimationFrame(() => { if (Math.abs(window.pageYOffset - posY) <= 1) { window.removeEventListener('scroll', scrollHandler); clearTimeout(failed); resolve(); } }); };
4. 优化事件绑定性能
给滚动事件添加passive: true选项,提升触屏设备上的滚动性能,同时避免重复绑定风险:
window.addEventListener('scroll', scrollHandler, { passive: true });
额外建议
优先使用CSS原生的scroll-snap-type和scroll-snap-align实现核心滚动吸附逻辑,减少JS手动滚动的干预,更好适配不同设备的原生滚动行为,从根源避免冲突。
内容的提问来源于stack exchange,提问作者Tasty
相关产品推荐
相关产品推荐

