1. 需求
開寶箱在一些商家營銷活動中也很常見,這個需求簡單,產品經理說就是做個動畫就好,那我們就可以自由發揮了。高保圖如下圖1.
圖1
開局一張圖,剩下的全靠自己編了,動作怎么動,先看看UI給的素材,看米下鍋。一張關閉的箱子圖片,如下圖2
圖2
一張打開的箱子,如下圖3
圖3
一張獎品背景圖片,是光芒,可以作為獎品的背景圖,如下圖4
圖4
雖然需求文檔中沒有給出這個動畫的具體需求,但可以根據產品的描述,可以把需求歸納一下,如下:
- 點擊“立即開啟”,先顯示半透明的蒙版,再顯示關閉的箱子,並且從小變大
- 請求接口,同時從關閉變成打開的箱子,在打開箱子的空白處顯示中獎結果
- 用光芒圖片作為獎品圖片的背景,並且光芒不斷地旋轉起來
- 點擊關閉,關閉整個中獎彈框
2. 思路
這個動畫相對簡單,可以直接使用css中的animation動畫,通過keyframe定義動畫幀來讓圖片從小變大,同時切換上面的圖2和圖3可以讓寶箱狀態從關閉變成打開,然后顯示獎品就有了。然后還有一個地方,就是獎品的背景是一個圓形光芒,可以讓它旋轉,或者不斷地變大變小,這樣看起來更加的生動。
3. 實現過程
3.1 蒙版
點擊按鈕首先彈出蒙版,這就沒啥好說的了,使用fix定位 + background + opacity可以做一個簡單的蒙版,代碼如下:
<!-- 抽獎按鈕 -->
<img class="treasure" src="./../assets/images/treasurebox.gif" @click="openBox" alt=""/>
<!-- 彈出層 -->
<div v-if="showBox" class="pop-up">
<div class="prize-box"></div>
css代碼如下:
.pop-up {
position: fixed;
z-index: 4;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
}
注意上面代碼中使用rgba作為背景色,最后一個參數是opacity,規定不透明度。從 0.0 (完全透明)到 1.0(完全不透明)。
3.2 開寶箱
寶箱圖片有2個,一個是關閉的,一個是打開的,要用一個動畫控制二者切換,並且還要掌握好他們的顯示時間這樣看起來是一個打開的過程,不過這里只有兩張圖片,無法看到打開過程,只能稍微模擬一下。如果要有整個過程的話,就要提供很多個中間狀態的寶箱圖片了。html代碼如下:
<div v-if="showBox" class="pop-up">
<div class="prize-box">
</div>
</div>
css代碼如下:
$aniDuration: 2s;
.prize-box {
position: relative;
width: 548px;
height: 739px;
margin: 81px auto auto auto;
animation: openBox $aniDuration ease-out 1s 1 forwards;
background: top/5% no-repeat url("./../assets/images/box@2x.png");
}
@keyframes openBox {
from {
background-position: center;
-webkit-background-size: calc(548px * 0.1) calc(739px * 0.1);
background-size: 5%;
width: calc(548px * 0.1);
height: calc(739px * 0.1);
background-image: url("./../assets/images/box@2x.png");
background-position: top;
}
50% {
background-position: center;
background-size: 50%;
width: calc(548px * 0.5);
height: calc(739px * 0.5);
background-image: url("./../assets/images/box@2x.png");
background-position: top;
}
80% {
background-position: center;
background-size: 110%;
width: calc(548px * 1.1);
height: calc(739px * 1.1);
background-position: top;
}
to {
background-position: center;
background-size: 548px 739px;
width: 548px;
height: 739px;
background-image: url("./../assets/images/boxopen@2x.png");
background-position: top;
}
}
代碼中給class為prize-box的容器定義了一個動畫openBox,用變量$aniDuration紀錄動畫持續時長,1秒后開始執行,最后停留在終態,時間函數(animation-timing-function)使用easy-out。在keyframe關鍵幀中修改了背景圖片大小,dom容器大小等css屬性,都是從小到大,並且在動畫的0%80%部分是顯示關閉寶箱,最后80%100%顯示開啟的寶箱。在動畫的80%處背景稍微變大一下,看起來有膨脹的效果。可以想想一下,這個動畫的整個過程是,關閉寶箱從小到大,變成開啟的寶箱,並且膨脹一下,最后恢復到原始大小。
animation的第三個屬性animation-timing-function是一個貝塞爾時間函數,可用的取值如下:
- linear
動畫以恆定速度運行。此關鍵詞表示緩沖函數 cubic-bezier(0.0, 0.0, 1.0, 1.0)。如下圖5。
圖5- ease
動畫緩慢開始,然后突然加速,最后緩慢移向目標。此關鍵詞表示緩沖函數cubic-bezier(0.25, 0.1, 0.25, 1.0)。它與 ease-in-out 類似,但它在開始時加速更快。如下圖6。
圖6- ease-in
動畫緩慢開始,然后逐漸加速直到結束,在結束點時突然停止。此關鍵詞表示緩沖函數 cubic-bezier(0.42, 0.0, 1.0, 1.0),如下圖7。
圖7- ease-in-out
動畫緩慢開始,然后加速,最后減速直至結束。此關鍵詞表示緩沖函數 cubic-bezier(0.42, 0.0, 0.58, 1.0)。開始時,其表現與 ease-in 函數類似;結束時,與 ease-out 函數類似。如下圖8。
圖8- ease-out
此動畫突然開始,然后逐漸減速直至結束。此關鍵詞表示緩沖函數 cubic-bezier(0.0, 0.0, 0.58, 1.0)。如下圖9。
圖9
貝塞爾時間函數的內容很多,並且很晦澀,這里不再展開討論。看看效果,如下圖10
圖10
3.3 請求接口
請求接口前需要定義好獎品,以便從接口中取出中獎獎品信息,代碼如下:
data() {
return {
showBox: false,
showPrize: false,
prizeList: [
{prizeId: "100860801", prizeName: "100元滿減券"},
{prizeId: "100860802", prizeName: "20元抵扣劵",},
{prizeId: "100860803", prizeName: "10元抵扣券"},
{prizeId: "100860804", prizeName: "1個月優惠員"},
{prizeId: "100860805", prizeName: "1元紅包"},
{prizeId: "100860806", prizeName: "5紅包"},
{prizeId: "100860807", prizeName: "1元抵扣券"},
{prizeId: "100860808", prizeName: "500元滿減券"},
{prizeId: "100860809", prizeName: "200元滿減券"}
],
title: ['發送給好友', '可增加一次開寶箱機會'],
actionBtn: {id: 1, title: '呼朋喚友,再開一次'},
prizeData: {prizeId: "100860801", prizeName: "100元移動話費"}, //抽獎信息獎信息
}
}
這里依然使用getRandomIntInclusive()方法從獎品數據中隨機取出一個獎品,模擬抽獎過程。代碼如下:
/* 開寶箱抽獎 */
openBox() {
this.showBox = true
setTimeout(() => {
this.showPrize = true
let index = this.getRandomIntInclusive(0, this.prizeList.length - 1)
this.prizeData = this.prizeList[index]
}, 3000)
},
/* 關閉按鈕 */
followAction() {
this.showBox = false
this.showPrize = false
},
//返回隨機數,大於等於min,小於等於max
getRandomIntInclusive(min, max) {
min = Math.ceil(min)
max = Math.floor(max)
return Math.floor(Math.random() * (max - min + 1)) + min //含最大值,含最小值
}
3.4 顯示獎品
開寶箱的動畫有了,剩下的就是請求接口,顯示獎品了。注意開啟的寶箱有兩處留白,這里要使用相對定位來固定獎品圖片,獎品名稱文案,抽獎提示文案,如下圖11
圖11
html代碼如下:
<!-- 彈出層 -->
<div v-if="showBox" class="pop-up">
<div class="prize-box">
<template v-if="showPrize">
<div class="prize">
<img :src="require('./../assets/images/prize/' + prizeData.prizeId + '.png')" alt="" class="img-prize"/>
</div>
<div class="prizetip">
<div>恭喜獲您獲得{{ prizeData.prizeName }}</div>
</div>
<div class="prizelead">
<div class="content" @click="followAction">
{{ actionBtn.title }}>
</div>
</div>
</template>
</div>
<img v-if="showPrize" class="close" src="./../assets/images/closebox@2x.png" @click="followAction" alt=""/>
</div>
css代碼如下:
// 獎品
.prize {
z-index: 5;
position: absolute;
left: 50%;
margin-left: -118px;
top: 190px;
left: 50%;
width: 219px;
height: 219px;
background-size: 219px 219px;
background-position: center;
align-content: center;
display: flex;
align-items: center;
justify-content: center;
.img-prize {
width: 180px;
height: 150px;
z-index: 6;
}
}
.prize:before {
content: "";
position: absolute;
z-index: 4;
width: 110%;
height: 110%;
background: center / contain no-repeat url("../assets/images/prizebg@2x.png");
animation: turn 6s linear infinite;
}
@keyframes turn{
0% { -webkit-transform: rotate(0deg); }
100%{ -webkit-transform: rotate(360deg); }
}
.prizetip {
z-index: 6;
position: relative;
top: 380px;
margin: 0 auto;
font-size: 28px;
font-family: HuipuMR;
color: rgba(51, 51, 51, 1);
height: 72px;
@include flex(center, center, column, nowrap);
div {
height: 40px;
line-height: 40px;
}
}
.prizelead {
position: relative;
top: 525px;
margin: 0 auto;
max-width: 374px;
height: 70px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(90deg, rgba(247, 231, 165, 1) 0%, rgba(255, 234, 114, 1) 100%);
box-shadow: 0px 4px 8px 0px rgba(203, 68, 15, 1);
border-radius: 40px;
.content {
text-align: center;
font-size: 28px;
color: rgba(191, 62, 11, 1);
line-height: 38px;
text-shadow: 0px 4px 8px rgba(203, 68, 15, 1);
}
}
注意,顯示了獎品之后我們還在獎品的背景,光芒四射圖片上設置了一個旋轉動畫,這個相對簡單,就是設置rotate從0deg到360deg。並且把這個背景使用了before偽類,這樣就不用再弄一個dom層了。
在最后加了一個關閉按鈕,這個不再贅述。
看下效果,如下圖12
圖12
4. 總結
本文介紹了如何使用css的animation動畫實現一個開寶箱抽獎的功能,主要就是animation+keyframe,相對簡單。