如今這么發(fā)達(dá)曼玩,想必大家都用餓了么點(diǎn)過餐吧鳞骤?當(dāng)你選擇商品加入購物車,小球飛入的動(dòng)畫是不是很炫酷黍判?豫尽,大體是下邊這個(gè)樣子
怎么樣,炫酷吧顷帖?今天我們也來試著實(shí)現(xiàn)這個(gè)動(dòng)畫美旧!
首先,你需要知道vue的狀態(tài)過度動(dòng)畫贬墩,官方文檔介紹的很詳細(xì)榴嗅,這里我就不多解釋了。作者語文底子不好震糖,直接上代碼了(使用vue-cli)录肯,詳細(xì)邏輯及思路都在代碼注釋中
<template>
<div class="demo">
<div class="addBtn" @click="addGoods"></div>
<div class="cart">
這是購物車
<div class="ball-wrapper" v-for="(ball, index) of balls" :key="index">
<transition
name="drop"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
<div class="ball" v-show="ball.show">
<!--這里為了做兩個(gè)維度的動(dòng)畫,因此需要多包一層吊说,外層做Y軸论咏,內(nèi)層做X軸動(dòng)畫-->
<div class="inner inner-hook"></div>
</div>
</transition>
</div>
</div>
</div>
</template>
<script>
export default {
name: "demo",
data() {
return {
balls: [
// 這里定義了多個(gè)ball,是因?yàn)榭赡芡瑫r(shí)有多個(gè)小球在動(dòng)畫中(快速點(diǎn)擊多次或者多個(gè)商品)
{
show: false
},
{
show: false
},
{
show: false
},
{
show: false
},
{
show: false
}
],
dropBalls: [] // 在動(dòng)畫中的小球集合
};
},
methods: {
addGoods(e) {
let el = e.target;
this.balls.forEach(v => {
if (!v.show) {
v.show = true; // 當(dāng)切換元素的display:block/none時(shí),會(huì)觸發(fā)vue的動(dòng)畫
v.el = el; // 將觸發(fā)點(diǎn)擊事件的“+”號(hào)保定道小球?qū)ο笊习渚奖惬@取動(dòng)畫初始時(shí)的位置
this.dropBalls.push(v); // 取一個(gè)小球加入動(dòng)畫隊(duì)列
return;
}
});
},
beforeEnter(el) {
let count = this.balls.length;
while (count--) {
// 將動(dòng)畫隊(duì)列中的小球厅贪,依次處理
let ball = this.balls[count];
if (ball.show) {
let rect = ball.el.getBoundingClientRect(); //拿到點(diǎn)擊的“+”號(hào)的位置,這里不直接取值(我是用的絕對(duì)定位,當(dāng)然可以直接取值)的原因是雅宾,商品列表中每個(gè)加號(hào)的位置是不固定的养涮,如果上下滑動(dòng)了,這個(gè)位置就不確定
let x = rect.left - 70; // 需要偏移的x向距離
let y = -(window.innerHeight - rect.top - 65); // 需要偏移的y向距離
el.style.display = ""; // 當(dāng)前狀態(tài)下,display值為none贯吓,將其置空懈凹。
// 這里需要注意了,小球飛入的動(dòng)畫分兩個(gè)維度悄谐,X軸和Y軸介评,因此
el.style.webkitTransform = `translate3d(0px, ${y}px, 0px)`; // 首先將“ball”Y向移動(dòng)至“+”好位置
el.style.transform = `translate3d(0px, ${y}px, 0px)`;
// 接著將“inner-hook”X向移動(dòng)至“+”號(hào)處,其實(shí)此時(shí)外層“ball”的X位置沒有動(dòng)爬舰,但因?yàn)楸尘吧鹊葮邮街粦?yīng)用于“inner-hook”上们陆,因此,視覺效果上情屹,這個(gè)小球是移動(dòng)到了“+”號(hào)的位置
let inner = el.getElementsByClassName("inner-hook")[0];
inner.style.webkitTransform = `translate3d(${x}px, 0, 0)`;
inner.style.transform = `translate3d(${x}px, 0, 0)`;
}
}
},
enter(el) {
/* eslint-disable no-unused-vars */
let rf = el.offsetHeight; // 主動(dòng)觸發(fā)瀏覽器重繪
this.$nextTick(() => {
el.style.webkitTransform = "translate3d(0, 0, 0)"; //接著將小球位置置為初始值坪仇,但css中設(shè)置了transition .8s,因此,動(dòng)畫效果就出來了
el.style.transform = "translate3d(0, 0, 0)";
let inner = el.getElementsByClassName("inner-hook")[0];
inner.style.webkitTransform = "translate3d(0, 0, 0)";
el.style.transform = "translate3d(0, 0, 0)";
});
},
afterEnter(el) {
let ball = this.dropBalls.shift(); //結(jié)束后垃你,將這個(gè)活動(dòng)中的小球刪除
if (ball) {
ball.show = false;
el.style.display = "none"; // 并且將其設(shè)為不可見
}
}
}
};
</script>
<style lang="stylus" scoped>
.demo
.addBtn
position: absolute;
top: 50px;
right: 50px;
width: 20px;
height: 20px;
background: blue;
border-radius: 50%;
.cart
position: absolute;
left: 30px;
bottom: 30px;
width: 100px;
text-align: center;
height: 50px;
line-height: 50px;
border: 1px solid #ccc;
.ball
position: fixed;
z-index: 100;
left: 70px;
bottom: 45px;
&.drop-enter-active
transition: all 0.8s cubic-bezier(0.49, -0.29, 0.75, 0.41);
.inner
width: 20px;
height: 20px;
border-radius: 50%;
background: red;
transition: all 0.8s;
</style>
分步操作如下圖:
好了椅文,今天就這么多了