11

抽奖动画 - 开宝箱抽奖

 2 years ago
source link: https://www.cnblogs.com/tylerdonet/p/15164824.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

抽奖动画 - 开宝箱抽奖

开宝箱在一些商家营销活动中也很常见,这个需求简单,产品经理说就是做个动画就好,那我们就可以自由发挥了。高保图如下图1.
image
图1
开局一张图,剩下的全靠自己编了,动作怎么动,先看看UI给的素材,看米下锅。一张关闭的箱子图片,如下图2
image
图2
一张打开的箱子,如下图3
image
图3
一张奖品背景图片,是光芒,可以作为奖品的背景图,如下图4
image
图4

虽然需求文档中没有给出这个动画的具体需求,但可以根据产品的描述,可以把需求归纳一下,如下:

  1. 点击“立即开启”,先显示半透明的蒙版,再显示关闭的箱子,并且从小变大
  2. 请求接口,同时从关闭变成打开的箱子,在打开箱子的空白处显示中奖结果
  3. 用光芒图片作为奖品图片的背景,并且光芒不断地旋转起来
  4. 点击关闭,关闭整个中奖弹框

这个动画相对简单,可以直接使用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/[email protected]");
}
@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/[email protected]");
      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/[email protected]");
      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/[email protected]");
      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是一个贝塞尔时间函数,可用的取值如下:

  1. linear
    动画以恒定速度运行。此关键词表示缓冲函数 cubic-bezier(0.0, 0.0, 1.0, 1.0)。如下图5。
    image
    图5
  2. ease
    动画缓慢开始,然后突然加速,最后缓慢移向目标。此关键词表示缓冲函数cubic-bezier(0.25, 0.1, 0.25, 1.0)。它与 ease-in-out 类似,但它在开始时加速更快。如下图6。
    image
    图6
  3. ease-in
    动画缓慢开始,然后逐渐加速直到结束,在结束点时突然停止。此关键词表示缓冲函数 cubic-bezier(0.42, 0.0, 1.0, 1.0),如下图7。
    image
    图7
  4. ease-in-out
    动画缓慢开始,然后加速,最后减速直至结束。此关键词表示缓冲函数 cubic-bezier(0.42, 0.0, 0.58, 1.0)。开始时,其表现与 ease-in 函数类似;结束时,与 ease-out 函数类似。如下图8。
    image
    图8
  5. ease-out
    此动画突然开始,然后逐渐减速直至结束。此关键词表示缓冲函数 cubic-bezier(0.0, 0.0, 0.58, 1.0)。如下图9。
    image
    图9

贝塞尔时间函数的内容很多,并且很晦涩,这里不再展开讨论。看看效果,如下图10
03%E8%83%8C%E6%99%AF%E5%BC%B9%E6%A1%86.gif
图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
image
图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/[email protected]" @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/[email protected]");
  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
image
图12

本文介绍了如何使用css的animation动画实现一个开宝箱抽奖的功能,主要就是animation+keyframe,相对简单。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK