如何在不使用jQuery的情况下应用该缓动过渡效果?
原生JavaScript实现滚动缓动过渡效果(附代码解析)
嘿,我来帮你拆解这段原生JS的滚动缓动代码,同时讲清楚不用jQuery怎么实现这类平滑滚动效果~
首先,先明确核心逻辑:原生JS实现缓动滚动,本质是通过分多次修改scrollTop值,每次的位移量由「缓动函数」计算,让滚动从快到慢(或先加速后减速),而不是一次性跳转到目标位置。
先拆解你找到的那段脚本
我们逐部分来看这个scrollTo函数:
function scrollTo(c,e,d){ // 设置默认缓动函数为easeInOutQuart d||(d=easeInOutQuart); var a=document.documentElement; // 兼容性处理:判断用document.documentElement还是body作为滚动容器 if(0===a.scrollTop){ var b=a.scrollTop; ++a.scrollTop; a=b+1===a.scrollTop--?a:document.body } b=a.scrollTop; // 处理参数:如果传的是DOM元素,就取它的offsetTop作为滚动目标 0>=e||("object"===typeof b&&(b=b.offsetTop),"object"===typeof c&&(c=c.offsetTop), // 核心动画逻辑的自执行函数 function(a,b,c,f,d,e,h){ function g(){ // 如果动画进度超出范围,直接跳到目标位置收尾 0>f||1<f||0>=d?a.scrollTop=c: // 用缓动函数计算当前应滚动到的位置 (a.scrollTop=b-(b-c)*h(f), // 更新动画进度,递归执行 f+=d*e,setTimeout(g,e)) } g() }(a,b,c,0,1/e,20,d)) };
关键细节解析:
滚动容器兼容性处理:
不同浏览器的scrollTop挂载对象不一样——有些在document.documentElement,有些在document.body。这段代码通过一个小测试(尝试修改documentElement.scrollTop看是否生效),自动选择正确的滚动容器,避免兼容性问题。参数灵活性:
函数支持两种传参方式:- 直接传数值:比如
scrollTo(1000, 500)表示500毫秒内滚动到垂直位置1000px - 传DOM元素:比如
scrollTo(document.getElementById('target'), 800)表示滚动到目标元素的顶部位置
- 直接传数值:比如
核心动画循环:
内部用setTimeout递归执行g函数,每20毫秒更新一次scrollTop:f是动画进度(从0到1),每次增加1/e * 20(保证总时长约为e毫秒)h(f)是缓动函数的计算结果,用来控制滚动的加速度——easeInOutQuart是「先加速后减速」的缓动效果,让滚动更自然。
补全你没写完的easeInOutQuart函数
这个缓动函数的完整实现是四次方曲线,公式如下:
function easeInOutQuart(t) { // t是0-1之间的进度值 return t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2; }
给你一个更易读、性能更好的简化版本
上面的代码是压缩过的,可读性差。我给你重构一个用requestAnimationFrame(比setTimeout更流畅,和浏览器刷新同步)的版本:
// 定义缓动函数:先加速后减速 function easeInOutQuart(t) { return t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2; } // 平滑滚动函数 function smoothScrollTo(target, duration = 500) { // 确定正确的滚动容器 const scrollContainer = document.documentElement.scrollTop !== 0 ? document.documentElement : document.body; const startPosition = scrollContainer.scrollTop; // 处理目标位置:支持DOM元素或数值 const targetPosition = typeof target === 'object' ? target.offsetTop : Number(target); const distance = targetPosition - startPosition; let startTime = null; // 用requestAnimationFrame执行动画 function animate(currentTime) { if (startTime === null) startTime = currentTime; const timeElapsed = currentTime - startTime; // 计算当前动画进度(0到1) const progress = Math.min(timeElapsed / duration, 1); // 用缓动函数计算当前滚动位置 const currentPosition = startPosition + distance * easeInOutQuart(progress); scrollContainer.scrollTop = currentPosition; // 未完成则继续执行 if (timeElapsed < duration) { requestAnimationFrame(animate); } } requestAnimationFrame(animate); }
使用示例
- 滚动到页面顶部:
smoothScrollTo(0, 600)(600毫秒完成) - 滚动到某个DOM元素:
smoothScrollTo(document.getElementById('about-section'), 800)
内容的提问来源于stack exchange,提问作者Joe278
相关产品推荐
相关产品推荐

