一、购物车小球实现与飞入动画
- 在
vue
的页面中定义一个小球,通过 v-show
使用 ballFlag
的值设置小球的显示与隐藏,ref
是小球的引用对象,代码如下所示:
<div class="ball" v-show="ballFlag" ref="ball"></div>
- 在
style
中,设置小球的样式,代码如下所示:
.ball {
width: 15px;
height: 15px;
border-radius: 50%;
background-color: red;
position: absolute;
z-index: 99;
top: 390px;
left: 146px;
}
- 在
data
中定义 ballFlag
,默认为false
,不显示,用来控制小球的隐藏和显示的标识符,代码如下所示:
data() {
return {
ballFlag: false
}
}
- 在
methods
中,定义 addToShopCar
方法,点击加入购物车后会触发,将 data
中的 ballFlag
的值取反,使其进行取反,进行小球的显示与隐藏,代码如下所示:
addToShopCar () {
this.ballFlag = !this.ballFlag
}
- 在之前定义小球的地方,添加
transition
动画,设置 @before-enter
、@enter
和 @after-enter
的动画绑定,代码如下所示:
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div class="ball" v-show="ballFlag" ref="ball"></div>
</transition>
- 在
methods
中,定义上面的动画,beforeEnter
是进入前动画,enter
是进入时动画,afterEnter
是离开后的动画,cubic-bezier(.4, -0.3, 1, .68)
是贝塞尔曲线动画,代码如下所示:
beforeEnter(el) {
el.style.transform = 'translate(0, 0)'
},
enter(el, done) {
el.offsetWidth
el.style.transform = 'translate(93px, 230px)'
el.style.transition = 'all 0.5s cubic-bezier(.4, -0.3, 1, .68)'
done()
},
afterEnter(el) {
this.ballFlag = !this.ballFlag
}
- 如果这样写,那么小球的移动距离就会写死。当不同屏幕分辨率的时候,就会显示不了。所以我们可以分析优化一下小球的动画思路:
- 先分析导致动画不准确的本质原因:我们把小球最终位移到的位置,已经局限在了某一分辨率下的 滚动条未滚动的情况下;
- 只要分辨率和 测试的时候不一样,或者 滚动条有一定的滚动距离之后,问题就出现了;
- 我们经过分析,得到结论:不能把位置的横纵坐标 直接写死了,而是应该根据不同情况,动态计算这个坐标值;
- 经过分析,得出解决思路:先得到徽标的横纵坐标,再得到小球的横纵坐标,然后让
y
值求差, x
值也求 差,得到的结果,就是横纵坐标要位移的距离 - 获取徽标和小球的位置,可以通过
domObject.getBoundingClientRect()
方法
getBoundingClientRect()
是用于获取某个元素相对于视窗的位置集合。集合中有top
, right
, bottom
, left
等属性,具体为:
rectObject.top
:元素上边到视窗上边的距离;rectObject.right
:元素右边到视窗左边的距离;rectObject.bottom
:元素下边到视窗上边的距离;rectObject.left
:元素左边到视窗左边的距离;
- 在
enter
中,通过 this.$refs.ball
获取小球的引用对象,然后再通过 getBoundingClientRect()
获取小球在页面中的位置。通过 document.getElementById
获取徽标的 id
值,然后再通过 getBoundingClientRect()
获取徽标在页面中的位置。通过 badgePosition.left - badgePosition.left
获取横坐标需要移动的距离,通过 badgePosition.top - badgePosition.top
获取纵坐标需要移动的距离,代码如下所示:
enter(el, done) {
el.offsetWidth
const ballPosition = this.$refs.ball.getBoundingClientRect()
const badgePosition = document.getElementById('badge').getBoundingClientRect()
const xDist = badgePosition.left - badgePosition.left
const yDist = badgePosition.top - badgePosition.top
el.style.transform = `translate(${xDist}px, ${yDist}px)`
el.style.transition = 'all 0.5s cubic-bezier(.4, -0.3, 1, .68)'
done()
}