这几天看到了基于vue仿饿了么购物车小球动画这一章,我的项目是基于vue2.x写的,所以视频里基于vue1.x的写法不适合我,于是按照文档改成了2.x版本的写法,这个动画的方式采用两层,一层是.ball的运动,一层是.inner的运动,可以将其写成一层只有.ball运动的写法,只需改变部分代码就行了,代码在注释里,记得样式代码也要改。
刚开始将视频里的代码改成了如下格式:
<div class="ball-container">
<transition-group name="drop"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div class="ball" v-for="(ball,index) in balls" v-bind:key="index" v-show="ball.show">
<div class="inner inner-hook"></div>
</div>
</transition-group>
</div>
transition-group是vue文档中用于列表过渡的,在这里的小球虽然是用v-for遍历出来的,但是运动时候还是单个单个的运动,用transition-group是可以写出来的,还是将它改成了如下代码,使之成为单个运动的方式:
<div class="ball-container" v-for="ball in balls">
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
name="drop">
<div class="ball" v-show="ball.show">
<div class="inner inner-hook">
</div>
</div>
</transition>
</div>
stylus代码如下:
.ball-container
.ball
position: fixed
left: 32px
bottom: 22px
z-index: 200
transition: all 0.4s linear
.inner
width: 16px
height: 16px
border-radius: 50%
background: rgb(0, 160, 220)
transition: all 0.4s linear
js代码如下,注意:
v-on:before-enter=”beforeEnter”
v-on:enter=”enter”
v-on:after-enter=”afterEnter”这是触发钩子函数的代码,必须要,具体的方法写在methods里:
drop(el) {
for (let i = 0; i < this.balls.length; i++) {
let ball = this.balls[i];
if (!ball.show) {
ball.show = true;
ball.el = el;
this.dropBalls.push(ball);
return;
}
}
},
beforeEnter: function (el) {
let count = this.balls.length;
while (count--) {
let ball = this.balls[count];
if (ball.show) {
/*获取加号的位置(小球动画开始的位置)*/
let rect = ball.el.getBoundingClientRect();
let x = rect.left - 32;
let y = -(window.innerHeight - rect.top - 22);
/*注释部分为动画为一层时代码*/
/*el.style.display = '';*/
/*el.style.webkitTransform=`translate3d(${x}px,${y}px,0)`;*/
/*el.style.transform = `translate3d(${x}px, ${y}px, 0)`;*/
el.style.display = '';
el.style.webkitTransform = `translate3d(0, ${y}px, 0)`;
el.style.transform = `translate3d(0, ${y}px, 0)`;
/*内层动画(这个动画在这里被分成两层,也可以一层)*/
let inner = el.getElementsByClassName('inner-hook')[0];
inner.style.webkitTransform = `translate3d(${x}px, 0, 0)`;
inner.style.transform = `translate3d(${x}px, 0, 0)`;
}
}
},
enter: function (el, done) {
/* eslint-disable no-unused-vars */
let rf = el.offsetHeight; /*触发浏览器重绘;*/
this.$nextTick(() => {
el.style.webkitTransform = 'translate3d(0, 0, 0)';
el.style.transform = 'translate3d(0, 0, 0)';
let inner = el.getElementsByClassName('inner-hook')[0];
inner.style.webkitTransform = 'translate3d(0, 0, 0)';
inner.style.transform = 'translate3d(0, 0, 0)';
el.addEventListener('transitionend', done);
});
},
afterEnter: function (el) {
let ball = this.dropBalls.shift();
if (ball) {
ball.show = false;
el.style.display = 'none';
}
}