前言
日常开发中我们经常遇到滚动条,当我们想要滚动条滚动到某个位置,可以直接设置元素scrollTo的值,不过该方法效果看起来很生硬,下面我们来自定义一个滚动方法,让效果看起来丝滑点。
滚动方法
我们想要滚动更加丝滑、可控,可以利用微积分的思路,把总的滚动位置分成n小份,每次只滚动一小份的距离,就能达到我们想要的效果。根据以上思路我们确定三个参数:
- toPosition:滚动条滚动的位置。
- duration:滚动的时间,达到我们可控的目的,该参数可以设置一个默认值。
- callback:回调函数,滚动后完成某些时间,当然该参数肯定可选。
function scrollTo (toPosition: number, duration: number, callback?: () => {}){}
第一步获取当前滚动条的位置,通过元素的sctollTo获取,考虑到页面嵌套情况,可以设置多种情况:
function getStartPosition() {
return (
document.body.scrollTop ||
document.documentElement.scrollTop ||
(document.body.parentNode as HTMLElement).scrollTop
)
}
我们将每一份移动的方法依旧是利用scrollTo:
function move(position: number){
document.body.scrollTop = position
document.documentElement.scrollTop = position
;(document.body.parentNode as HTMLElement).scrollTop = position
}
下面就是重点获取位移距离,我们想要的平滑效果其实跟animation的曲线运动效果其实是一样的,所以我们可以利用animation曲线运动的函数,根据这个函数得到位移距离。下面我们就选用ease-in-out作为效果:
//t 当前时间 b开始位移 c结束位移 d总时间
function easeInOut(t: number, b: number, c: number, d: number){
t /= d / 2
if (t < 1) {
return (c / 2) * t * t + b
}
t--
return (-c / 2) * (t * (t - 2) - 1) + b
}
以上b、c、d都是固定的,简单理解就是数学中的一个函数,传入t得到距离。当前时间从0开始,设置自己想要的步长,用当前时长与总时长做对比,如果小于就将时间加上步长重复上面行为,否则执行回调函数。很明显这里我们需要用到迭代,并且为了更好的动画效果,采用requestAnimationFrame方法:
function requestAnimFrame(function () {
//如果requestAnimationFrame获取不到就用setTimeout
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
(window as any).mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60)
}
)
})()
通过以上分析,我们就能得到想要的平滑滚动函数:
function scrollTo(
toPosition: number,
duration: number,
callback?: () => {}
) {
const start = getStartPosition()
const change = to - start
const step = 20
let currentTime = 0
duration = typeof duration === 'undefined' ? 500 : duration
const animateScroll = function () {
currentTime += step
const val = easeInOutQuad(currentTime, start, change, duration)
move(val)
if (currentTime < duration) {
requestAnimFrame(animateScroll)
} else {
if (callback && typeof callback === 'function') {
callback()
}
}
}
animateScroll()
}
总结
以上就是平滑滚动实现的过程,重点是获取位移距离的函数,利用了animation曲线速度的函数,我们可以根据自己的需要去调用对应的函数。