用requestAnimationFrame实现的滚动动画为什么偶尔会卡顿?
在做页面导航平滑滚动时,我用requestAnimationFrame写了个滚动函数,但偶尔会出现动画卡顿的情况,特别是在低端设备上。代码逻辑是这样的:
function smoothScroll(target) {
const step = () => {
const diff = target - window.scrollY;
if (Math.abs(diff) < 0.5) return;
window.scrollBy(0, diff * 0.1);
requestAnimationFrame(step);
};
requestAnimationFrame(step);
}
我尝试过把diff * 0.1改成更小的系数,也调整过raf的调用时机,但问题依旧。特别是当快速连续点击导航栏时,滚动会突然变慢甚至停顿几帧。这是不是跟浏览器渲染队列有关?有没有更好的优化方法?
我们可以通过加一个状态锁来解决这个问题,确保同一时间只有一个滚动动画在运行。另外,你的算法里用的是相对滚动
window.scrollBy,这确实容易出现累积误差,建议改成绝对定位的方式。给你一个改进版本:
这里做了几个关键改动:首先是加了
isScrolling锁,防止重复触发;其次是用了绝对定位window.scrollTo,避免累积误差;最后加入了简单的缓动效果,让动画更平滑。要注意的是,在实际项目中,你还得考虑一些边界情况,比如用户手动滚动时应该中断动画,或者目标元素被删除的情况要做异常处理。这些都是潜在的安全隐患点,防止因为异常导致页面崩溃。
对了,如果你发现低端设备上还是不够流畅,可以考虑把
duration时间缩短到300ms左右,这样虽然动画快了点,但能显著提升响应速度。性能和体验有时候就是个权衡的过程。