如何用纯JavaScript实现类似jQuery的平滑滚动到指定位置
纯JavaScript实现jQuery式平滑滚动到指定位置
要实现和$('html, body').animate({scrollTop: y}, 400)完全一致的效果,核心是模拟jQuery默认的swing缓动曲线和400ms的动画时长,用requestAnimationFrame实现流畅的帧动画,以下是完整实现函数:
function smoothScrollTo(y, duration = 400) { // 获取当前滚动位置 const startScroll = window.pageYOffset; // 计算需要滚动的距离 const scrollDistance = y - startScroll; // 记录动画开始时间 const animationStart = performance.now(); // 帧动画回调函数 function animateScroll(currentTime) { const timePassed = currentTime - animationStart; // 计算动画进度(限制在0-1区间) const progress = Math.min(timePassed / duration, 1); // 模拟jQuery默认的swing缓动效果(替代生硬的线性动画) const easeProgress = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2; // 滚动到当前计算的位置 window.scrollTo(0, startScroll + scrollDistance * easeProgress); // 动画未完成则继续请求下一帧 if (timePassed < duration) { requestAnimationFrame(animateScroll); } } // 启动动画 requestAnimationFrame(animateScroll); }
关键细节说明
- 缓动曲线匹配:jQuery的
animate默认使用swing缓动而非线性动画,上述代码通过二次贝塞尔公式模拟了完全一致的动画节奏,避免滚动生硬。 - 时长对齐:默认参数设为400ms,和原jQuery代码完全匹配,也可根据需求自行调整。
- 边界处理:用
Math.min(progress, 1)确保动画结束时精准到达目标位置,不会出现过度滚动。 - 兼容性:
requestAnimationFrame和performance.now()支持所有现代浏览器(包括IE10+),满足生产环境需求。
导航场景使用示例
针对你提到的固定导航点击滚动需求,只需获取目标区块的垂直偏移量,调用函数即可:
// 给导航项绑定点击事件 document.querySelectorAll('.nav-item').forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); // 获取目标区块ID const targetId = this.getAttribute('href').slice(1); const targetElement = document.getElementById(targetId); if (targetElement) { // 减去固定导航高度,避免区块被导航遮挡 const targetTop = targetElement.offsetTop - document.querySelector('.fixed-nav').offsetHeight; // 执行平滑滚动 smoothScrollTo(targetTop); } }); });
为什么不用原生scrollTo({behavior: 'smooth'})?
原生平滑滚动虽然简单,但无法自定义动画时长(由浏览器决定,通常不是400ms),也无法精确匹配jQuery的缓动曲线,对于需要严格对齐原效果的场景,手动实现帧动画是更可靠的选择。
内容的提问来源于stack exchange,提问作者Paul Z.
相关产品推荐
相关产品推荐

