如何在滚动时应用缓动过渡效果?不使用jQuery
不用jQuery实现滚动缓动过渡的方案(附代码拆解)
嘿,我来帮你把这段看起来有点绕的原生JS滚动代码拆解清楚,同时给你讲明白不用jQuery怎么实现平滑滚动的核心逻辑~
核心原理
原生JS实现滚动缓动,本质就是逐帧修改页面的滚动位置,配合缓动函数让滚动速度呈现自然的加速/减速曲线,而不是瞬间跳到目标位置。常用的实现方式是用requestAnimationFrame(比setTimeout更流畅,和浏览器刷新同步)或者setTimeout来循环更新scrollTop值。
拆解你找到的那段脚本
先把完整的代码补全(你给的easeInOutQ...应该是easeInOutQuart),然后逐部分解释:
function scrollTo(c,e,d){ d||(d=easeInOutQuart); // 若没传缓动函数,默认用easeInOutQuart var a=document.documentElement; // 兼容性处理:判断当前浏览器的滚动根元素是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)) }; // 完整的缓动函数:先加速、后减速的四次方曲线 function easeInOutQuart(t) { return t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2; }
关键部分解释:
兼容性处理:
老浏览器里,滚动根元素可能是document.documentElement(比如Chrome)或者document.body(比如老IE),这段代码通过临时修改scrollTop来判断哪个元素能生效。参数处理:
c可以是目标滚动的像素值,也可以是DOM元素(自动取元素的offsetTop)e是动画持续时间(毫秒)d是自定义缓动函数,默认用easeInOutQuart
动画循环:
用setTimeout每20ms执行一次g(),每次计算当前的滚动进度f(从0到1),然后用缓动函数h(f)把进度转换成符合动画曲线的值,最后修改scrollTop。
更易理解的简化版实现
上面的代码为了兼容性写得比较紧凑,这里给你一个更清晰的版本,用requestAnimationFrame实现更流畅的滚动:
// 定义缓动函数:先加速后减速,让滚动更自然 function easeInOutQuart(progress) { return progress < 0.5 ? 8 * Math.pow(progress, 4) : 1 - Math.pow(-2 * progress + 2, 4) / 2; } // 平滑滚动函数 function smoothScrollTo(target, duration = 500) { // 获取当前滚动位置 const startScroll = window.pageYOffset || document.documentElement.scrollTop; // 处理目标:如果是DOM元素,取它的顶部偏移量;如果是数字直接用 const targetScroll = typeof target === 'object' ? target.offsetTop : target; const scrollDistance = targetScroll - startScroll; let startTime = null; // 动画核心:用requestAnimationFrame同步浏览器刷新 function animate(currentTime) { if (!startTime) startTime = currentTime; // 计算已过去的时间占总时长的比例(进度0-1) const timeElapsed = currentTime - startTime; const progress = Math.min(timeElapsed / duration, 1); // 应用缓动函数,得到缓动后的进度 const easedProgress = easeInOutQuart(progress); // 更新滚动位置 window.scrollTo(0, startScroll + scrollDistance * easedProgress); // 如果动画还没结束,继续调用 if (timeElapsed < duration) { requestAnimationFrame(animate); } } requestAnimationFrame(animate); } // 使用示例 // 1. 滚动到id为"about-section"的元素,持续600ms smoothScrollTo(document.getElementById('about-section'), 600); // 2. 直接滚动到Y轴1200px的位置,用默认500ms时长 smoothScrollTo(1200);
缓动函数的作用
缓动函数决定了滚动的速度变化曲线,比如:
easeInOutQuart:先缓慢加速,到中间后缓慢减速,滚动体验最自然- 你也可以换成其他缓动函数,比如匀速(
function(t){return t})、先快后慢(easeOutQuart)等,只需要修改easeInOutQuart的实现即可。
内容的提问来源于stack exchange,提问作者Joe278
相关产品推荐
相关产品推荐

