web 实现滑动阻尼

edge_sky Lv2

原生 JS 实现

首先需要禁用滚轮对网页的滚动

1
2
3
4
5
6
7
8
9
// 一个指向 DOM 的函数
const el = document.documentElement
// 定义一个函数,用于禁用默认时间
const onWheel = (e) => {
e.preventDefault(); // 阻止默认事件,停止滚动
}
// 在 DOM 上添加滚轮的监听器,触发 onWheel 函数
// 添加 passive: false 表示该监听器不是被动监听器,防止方法不生效
el.addEventListener('wheel', onWheel, { passive: false });

绘制帧函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Silky {
timeRecord = 0 // 回调时间记录

constructor({ content } = {}) {
this.content = content || document.documentElement
const onWeel = (e) => {
e.preventDefault(); // 阻止默认事件,停止滚动
}
this.content.addEventListener('wheel', onWeel, { passive: false });
}
raf(time) {
const deltaTime = time - (this.timeRecord || time);
this.timeRecord = time;
console.log(deltaTime * 0.001) // 单位转化为秒,该值后面计算时会用到
}
}

// 创建一个实例
const silky = new Silky({<这里可以传入容器元素>})

// 循环绘制动画
function raf(time) {
silky.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);

实现虚拟滚动来代替鼠标滚动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 在 Silky 添加一下参数和方法
class Silky {
timeRecord = 0 // 回调时间记录
targetScroll = 0 // 当前滚动位置
animatedScroll = 0 // 动画滚动位置
from = 0 // 记录起始位置
to = 0 // 记录目标位置
........

// 虚拟滚动方法
onVirtualScroll(target) {
this.to = target;
this.onUpdate = (value) => {
this.animatedScroll = value; // 记录动画距离
this.content.scrollTop = this.animatedScroll; // 设置滚动
this.targetScroll = value; // 记录滚动后的距离
}
}
}

在滚动时间中调用 onVirtualScroll

1
2
3
4
const onWeel = (e) => {
e.preventDefault(); // 阻止默认事件,停止滚动
this.onVirtualScroll(this.targetScroll + e.deltaY);
}

添加 advance 方法,用于更新视图

1
2
3
4
5
6
7
8
raf(time) {
......
this.advance()
}
advance() {
const value = this.to
this.onUpdate?.(value);
}

线性插值实现阻尼感

  • 标题: web 实现滑动阻尼
  • 作者: edge_sky
  • 创建于 : 2024-05-20 22:02:18
  • 更新于 : 2024-07-01 22:52:55
  • 链接: https://edgesky.cn/2024/05/20/滑动阻尼/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。