# 使用 Konva.Tween 实现拖拽后的惯性动画
在现代 Web 应用中,为用户提供流畅自然的交互体验至关重要。通过为拖拽操作添加惯性效果,我们可以让应用感觉更加生动和自然。
# 准备工作
在开始之前,确保已安装 Konva.js 库。
npm install konva |
或者说直接在 HTML 中直接引用
<script src="https://unpkg.com/konva@8.3.10/konva.min.js"></script> |
# 创建场景和节点
- 创建一个场景和一个节点,并添加到场景中。
- 每次拖拽时都计算速度(与上次拖拽位置的差值)
- 创建一个 Tween 对象,并设置其属性为节点的位置和速度
<script src="https://unpkg.com/konva@8.3.10/konva.min.js"></script> | |
<div id="container"></div> | |
<script> | |
// 创建舞台和图层 | |
const width = window.innerWidth; | |
const height = window.innerHeight; | |
const stage = new Konva.Stage({ | |
container: "container", | |
width: width, | |
height: height, | |
}); | |
let layer = new Konva.Layer(); | |
stage.add(layer); | |
let rect = new Konva.Rect({ | |
x: 50, | |
y: 50, | |
width: 100, | |
height: 50, | |
fill: "green", | |
draggable: true, | |
}); | |
layer.add(rect); | |
layer.draw(); | |
let lastTime = 0; | |
let lastPos = null; | |
let lastVelocity = 0; | |
let lastVelocitx = 0; | |
function calculateVelocity() { | |
if (lastTime) { | |
const dt = (Date.now() - lastTime) ; | |
const dx = rect.x() - lastPos.x; | |
const dy = rect.y() - lastPos.y; | |
if (dt === 0) { | |
lastVelocitx = 0; | |
lastVelocity = 0; | |
} else { | |
lastVelocitx = dx / dt; | |
lastVelocity = dy / dt; | |
} | |
// console.log('Velocity:', lastVelocity); | |
} | |
lastTime = Date.now(); | |
lastPos = { x: rect.x(), y: rect.y() }; | |
} | |
rect.on("dragstart", () => { | |
lastTime = Date.now(); | |
lastPos = { x: rect.x(), y: rect.y() }; | |
}); | |
rect.on("dragmove", () => { | |
calculateVelocity(); | |
}); | |
rect.on("dragend", () => { | |
console.log(lastVelocitx, lastVelocity); | |
const targetX = rect.x() + lastVelocitx * 100; // 根据速度预测终点 | |
const targetY = rect.y() + lastVelocity * 100; | |
// 使用 Tween 创建惯性动画 | |
new Konva.Tween({ | |
node: rect, | |
duration: 1, // 动画持续时间 | |
easing: Konva.Easings.EaseOut, // 缓动函数 | |
x: targetX, | |
y: targetY, | |
}).play(); | |
}); | |
</script> |
# Tween 属性详解
# 核心属性说明
node(必填)
- 类型:
Konva.Node
- 作用:指定要应用动画的节点对象(如
rect
circle
等) - 示例:
node: rect
- 类型:
duration(必填)
- 类型:
Number
- 作用:动画持续时间(单位:秒)
- 示例:
duration: 1
表示 1 秒完成动画 - 注意:结合
easing
函数可实现缓动效果
- 类型:
easing
- 类型:
Function
- 作用:控制动画的缓动曲线
- 常用预设:
Konva.Easings.Linear
线性匀速Konva.Easings.EaseIn
先慢后快Konva.Easings.EaseOut
先快后慢(适合惯性效果)Konva.Easings.EaseInOut
慢 - 快 - 慢
- 类型:
目标属性
- 类型:
Number
- 作用:指定节点要动画到的目标属性值(可设置多个)
- 示例:
x: targetX, y: targetY, rotation: 360
- 类型:
# 高级配置
onFinish
- 类型:
Function
- 作用:动画结束时的回调函数
- 示例:
onFinish: function() {
console.log('动画完成');
}
- 类型:
onUpdate
- 类型:
Function
- 作用:动画每帧更新时的回调
- 示例:
onUpdate: function() {
layer.draw(); // 手动重绘图层
}
- 类型:
repeat
- 类型:
Number
- 作用:动画重复次数(0 表示不重复)
- 示例:
repeat: 2
动画将执行 3 次(初始 1 次 + 重复 2 次)
- 类型:
yoyo
- 类型:
Boolean
- 作用:是否开启往返动画(需要配合 repeat 使用)
- 示例:
yoyo: true
动画会正向播放后反向播放
- 类型: