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,相对简单。