Vue实现购物车抛物线动画

前言

抛物线动画应用场景较多,在购物车页面比较常见,那么,怎么来实现这样一个动画?

先看一下Demo图。


图片名称

实现原理及步骤

  1. 动态计算每一个加号到购物车的距离;

    图片名称
1
2
3
4
5
6
7
8
9
10
11
12
// 加号到顶部的距离
let iconTop = this.$refs.banner.$el.clientHeight + this.$refs['goods-' + id][0].offsetTop + this.$refs['goods-' + id][0].clientHeight - 6
// 商品列表滚动的距离
const scrollTop = this.$refs.list.scroll.wrapperOffset.top - this.$refs.list.scroll.y + RESERVED_HEIGHT
// 向上滚动
if (scrollTop > 0) {
iconTop = iconTop - scrollTop
}
// 加号到左边的距离
const iconLeft = window.innerWidth - this.$refs['add-' + id][0].clientWidth - 12
const x = iconLeft - this.$refs.cart.offsetLeft - this.$refs.cart.clientWidth / 2
const y = window.innerHeight - (this.$refs.cartView.clientHeight - this.$refs.cart.offsetTop - this.$refs.cart.clientHeight / 2) - iconTop + 10
  1. 利用css3 动画。translate来做位移,从加号图标按钮到购物车按钮的x、y方向发生的位移距离。rotate做图标旋转,让动画更加真实;
  2. 根据抛物线方程式y=a*x^2^,计算出每一个阶段加号图标应该出现的位置;

    1
    2
    // 计算a的值
    const a = y / (x * x)
  3. 利用create-keyframe-animation,把计算好的js代码转义成CSS动画代码,并绑定到对应document的node(加号图标)上。

  4. 动画结束后,进行相关操作。购物车放大缩小一下,价格以及数量增加。
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// 取消选择商品
unselectGoods (id) {
this.goodsList.forEach(goods => {
if (goods.id === id && goods.selectCount > 0) {
if (goods.iconDisabled) {
return
}
goods.selectCount--
return 0
}
})
},
// 选择商品
selectGoods (id) {
this.goodsList.forEach(goods => {
if (goods.id === id && goods.selectCount < goods.surplus) {
if (goods.iconDisabled === true) {
return
}
goods.iconDisabled = true
const _self = this
this.paoAnimation(id, function () {
// 抛物线动画结束事件
animations.runAnimation(_self.$refs.cart, 'cartScale')
goods.selectCount++
goods.iconDisabled = false
})
return 0
}
})
},
// 抛物线动画
paoAnimation (id, callback) {
// 加号到顶部的距离
let iconTop = this.$refs.banner.$el.clientHeight + this.$refs['goods-' + id][0].offsetTop + this.$refs['goods-' + id][0].clientHeight - 6
// 商品列表滚动的距离
const scrollTop = this.$refs.list.scroll.wrapperOffset.top - this.$refs.list.scroll.y + RESERVED_HEIGHT
// 向上滚动
if (scrollTop > 0) {
iconTop = iconTop - scrollTop
}
// 加号到左边的距离
const iconLeft = window.innerWidth - this.$refs['add-' + id][0].clientWidth - 12
const x = iconLeft - this.$refs.cart.offsetLeft - this.$refs.cart.clientWidth / 2
const y = window.innerHeight - (this.$refs.cartView.clientHeight - this.$refs.cart.offsetTop - this.$refs.cart.clientHeight / 2) - iconTop + 10
const a = y / (x * x)
let animation = {}
for (let i = 0; i <= 10; i++) {
animation[(i * 10) + '%'] = {transform: `translate(${-i / 10 * x}px, ${(-i / 10 * x) * (-i / 10 * x) * a}px) rotateZ(${360 * (1 - i / 10)}deg)`}
}
animations.registerAnimation({
name: 'move-' + id,
animation,
presets: {
duration: 250,
easing: 'linear',
fillMode: 'forwards',
resetWhenDone: true
}
})
animations.runAnimation(this.$refs['add-' + id][0], 'move-' + id, callback)
},
// 缩放动画
registerScalAnimation () {
const animation = {
'0%': {transform: `scale(1)`},
'25%': {transform: `scale(1.1)`},
'50%': {transform: `scale(1.2)`},
'75%': {transform: `scale(1.1)`},
'100%': {transform: `scale(1)`}
}
animations.registerAnimation({
name: 'cartScale',
animation,
presets: {
duration: 300,
resetWhenDone: true
}
})
},

注意事项

  1. 点我[具体代码实现]
  2. copy一个加号图标用来做动画,原来的按钮还是放在原来的位置。
  3. 动画过程中禁止再次点击
  4. 在使用create-keyframe-animation时,为了使动画可以重复使用,需要加resetWhenDone: true。
  5. 推荐使用CSS3动画生成器
坚持原创技术分享,您的支持将鼓励我继续创作!