Skip to content

Instantly share code, notes, and snippets.

@Caldis
Last active March 16, 2018 13:48
Show Gist options
  • Save Caldis/cca942e448ddb8a04a2004ebaf2208cd to your computer and use it in GitHub Desktop.
Save Caldis/cca942e448ddb8a04a2004ebaf2208cd to your computer and use it in GitHub Desktop.
Capture and smooth the scrolling for target dom
const view = document.querySelector("#page>div")
class scroll {
constructor({ target, interpulator, precision }) {
// values
this.target = target // 目标
this.precision = precision // 精确度
this.interpulator = interpulator // 插值器
this.timer = null // 计时器引用
this.looping = false // 是否正在循环
this.scrollCurrL1 = { x: 0, y: 0 } // 当前滚动距离
this.scrollPoolL1 = { x: 0, y: 0 } // 累计滚动距离
this.scrollCurrL2 = { x: 0, y: 0 } // 当前滚动距离
this.scrollPoolL2 = { x: 0, y: 0 } // 累计滚动距离
this.scrollDelta = { x: 0, y: 0 } // 滚动方向(保存上一次滚动的数值)
// Bind class function
this.tach = this.tach.bind(this)
this.detach = this.detach.bind(this)
this.startLoop = this.startLoop.bind(this)
this.looper = this.looper.bind(this)
this.stopLoop = this.stopLoop.bind(this)
this.capture = this.capture.bind(this)
this.post = this.post.bind(this)
}
// 钩子
tach() {
this.target.addEventListener('wheel', this.capture, false)
}
detach() {
this.target.removeEventListener('wheel', this.capture, false)
}
// 处理循环
startLoop({ force }={}) {
if (force || !this.looping) this.timer = window.requestAnimationFrame(this.looper)
this.looping = true
}
looper() {
// 获取插值结果
const pulse = {
x: this.interpulator({ curr: this.scrollCurrL2.x, dest: this.scrollPoolL2.x }),
y: this.interpulator({ curr: this.scrollCurrL2.y, dest: this.scrollPoolL2.y })
}
// 更新当前滚动位置
this.scrollCurrL2.x += pulse.x
this.scrollCurrL2.y += pulse.y
// 更新滚动结果
this.post(this.scrollCurrL2)
// 根据处理结果选择是否需要迭代循环
Math.abs(this.scrollPoolL2.x-this.scrollCurrL2.x)>this.precision ||
Math.abs(this.scrollPoolL2.y-this.scrollCurrL2.y)>this.precision ?
this.startLoop({ force: true }):
this.stopLoop()
}
stopLoop() {
this.looping && window.cancelAnimationFrame(this.timer)
this.looping = false
}
// 截取器
capture(e) {
const { deltaX, deltaY } = e
// 归一化处理
const x = normalize.max(deltaX, 100)
const y = normalize.max(deltaY, 100)
// 更新目标值
if ((this.scrollPoolL2.x-this.scrollCurrL2.x)*x>=0) {
this.scrollPoolL2.x += x
} else {
this.scrollPoolL2.x = this.scrollCurrL2.x+x
}
if ((this.scrollPoolL2.y-this.scrollCurrL2.y)*y>=0) {
this.scrollPoolL2.y += y
} else {
this.scrollPoolL2.y = this.scrollCurrL2.y+y
}
// 更新Delta值
this.scrollDelta.x = x
this.scrollDelta.y = y
// 启动循环
this.startLoop()
}
// 发送器
post({ x, y }) {
this.target.style.transform = `translate(${x}px, ${y}px)`
}
}
// 插值器
const Interpulator = {
lerp: ({ damping }) => ({ curr, dest }) => (dest-curr)*damping
}
// 归一化
const normalize = {
max: (val, limit) => Math.max(Math.abs(val), limit) * Math.sign(val),
min: (val, limit) => Math.min(Math.abs(val), limit) * Math.sign(val),
}
// 运行
const lerp = Interpulator.lerp({ damping: 0.1 })
const scroller = new scroll({ target: view, interpulator: lerp, precision: 0.1 })
scroller.tach()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment