better-scroll-blog
better-scroll-blog copied to clipboard
momentum(惯性滚动实现原理)
何时进行惯性滚动?
作用:当快速在屏幕中滑动一段距离后(手指离开),根据这段滑动的时间和距离代入到公式,求出最后滚动到的位置,并进行滚动动画。
在 _end
方法中调用了 momentum 来计算最后的位置。
// start momentum animation if needed
/* 必须开启 momentum 配置,滑动的时间小于 momentumLimitTime,且滑动的距离要超过 momentumLimitDistance (px)位置 */
if (this.options.momentum && duration < this.options.momentumLimitTime && (absDistY > this.options.momentumLimitDistance || absDistX > this.options.momentumLimitDistance)) {
let momentumX = this.hasHorizontalScroll ? momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options)
: {destination: newX, duration: 0}
let momentumY = this.hasVerticalScroll ? momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options)
: {destination: newY, duration: 0}
newX = momentumX.destination
newY = momentumY.destination
time = Math.max(momentumX.duration, momentumY.duration)
this.isInTransition = true
} else {
// code...
}
- momentum 方法中传入了一大推参数,下面看如何使用!
momentum.js
/**
* current 结束位置
* start 开始位置
* time 时长
* lowerMargin 滚动区域 maxScroll
* wrapperSize 当滚动超过边缘的时候会有一小段回弹动画 (wrapperSize = bounce)
*
* distance 距离
* speed 速度
* deceleration 减速度(系数) 0.001
* destination 目的地
*/
export function momentum(current, start, time, lowerMargin, wrapperSize, options) {
let distance = current - start
let speed = Math.abs(distance) / time
let {deceleration, itemHeight, swipeBounceTime, wheel, swipeTime} = options
let duration = swipeTime
// wheel: 为 picker 组件时,加大回弹系数
let rate = wheel ? 4 : 15
// 公式:惯性拖拽 = 最后的位置 + 速度 / 摩擦系数 * 方向
let destination = current + speed / deceleration * (distance < 0 ? -1 : 1)
// picker 组件时,将计算的位置取整
if (wheel && itemHeight) {
destination = Math.round(destination / itemHeight) * itemHeight
}
// 目的地(超过)最大的滚动范围 maxScroll
if (destination < lowerMargin) {
// 是否开启回弹
destination = wrapperSize ? lowerMargin - (wrapperSize / rate * speed) : lowerMargin
duration = swipeBounceTime
} else if (destination > 0) {
destination = wrapperSize ? wrapperSize / rate * speed : 0
duration = swipeBounceTime
}
// 如果未触发以上两种条件(未到达边界),则使用最初计算出来的位置
return {
destination: Math.round(destination),
duration
}
}
- 得出值后,在使用
scrollTo
进行滚动。
小结
现在,我们已经知道了这个 momentum 函数的实现,公式:惯性拖拽 = 最后的位置 + 速度 / 摩擦系数 * 方向。