本文介绍一个lao虎机抽奖动画的实现,lao虎机抽奖在各类商家营销活动中非常常见,这里主要介绍动画的实现过程,其他细节不做详细分析。

ps:lao虎机是敏感词,博客园不允许出现,所有老用拼音。

1. 需求

UI给到的蓝湖如下截图1



图1

  • 三栏图片,每栏图片是一样的,都包含所有的奖品图片。
  • 点击抽奖三栏图片从左到右依次开始上下滚动,从慢到块,滚动几轮后根据抽奖结果固定图片位置。
  • 如果中奖三栏显示同一张奖品图片,否则随机显示三张奖品图片。最后弹出抽奖结果弹框。

2. 整体思路

2.1 滚动

说到滚动,首先想到的是scroll,但是scroll会有滚动条出现。并且需求要求先滚动几轮,这个使用scroll的话我暂时想不出什么好的办法。

然后想到可以使用background-img结合background-repeat,background-position-y来实现这个功能,简单说就不断地修改背景图片的background-position-y,并且设置背景重复显示,这样看起来就是奖品图片在滚动了。

2.2 jquery动画

虽然可以使用css中的animation动画来让背景滚动,但是这里有个问题,在开始滚动图片同要去请求接口,在接口有了结果之后要根据结果来固定图片位置,使用keyframe的话要动态设置关键帧,这也很麻烦。

其实jquery提供了响应的api来修改元素的尺寸信息,和尺寸相关的都可以使用jquery动画。参考jquery文档如下:

所有用于动画的属性必须是数字的,除非另有说明;这些属性如果不是数字的将不能使用基本的jQuery功能。(例如,width, height或者left可以执行动画,但是background-color不能,除非使用jQuery.Color()插件。)属性值的单位像素(px),除非另有说明。单位em 和 %需要指定使用。

另外,背景开始滚动的时候是空转的,然后等到有抽奖结果之后在原来的background-position-y的基础上加上一个值,意思再滚动一个距离,固定在奖品图片上。这个需求和jquery动画属性中“相对值”的概念不谋而合。参考下面的jquery引文。

动画属性也可以是一个相对值。如果提供一个以+= 或 -=开始的值,那么目标值就是以这个属性的当前值加上或者减去给定的数字来计算的。

等待接口有响应之后还要播放第二个动画固定奖品,这时就要再播放一个动画,jquery已经想到了这个问题,所有提供一个done回调方法,如下:

done

Type: Function( Promise animation, Boolean jumpedToEnd )

在动画完成时执行的函数。 (他的Promise对象状态已完成). (version added: 1.8)..

2.3 尺寸问题

这个动画中尺寸问题至关重要,因为要对准奖品图片,尺寸稍有差别,就不容易设置好位置。还有UI给到我们的需求一般都是px,我们的vue项目中使用到“postcss-plugin-px2rem”插件会将px修改成相对的尺寸单位rem。postcss-plugin-px2rem配置如下:

'postcss-plugin-px2rem': {
rootValue: 75,
unitPrecision: 8,
propWhiteList: [],
propBlackList: [],
selectorBlackList: [],
ignoreIdentifier: false,
replace: true,
mediaQuery: false,
minPixelValue: 3,
exclude: /vant/i
}

这里最关键的信息是rootValue,设计稿给到的屏幕宽度是750px,这个值被换算成rem是750px/75=10rem,我们代码中所有的尺寸都会按照这个公式换算成rem。

然后我们动画中计算background-position-y的时候也要像这样换算一下,不然也有可能对不准奖品图片。

还有每个奖品图片在整张背景图中的次序也要先弄清楚,这里记在一个数组中,最后固定奖品图片的时候用到。如下:

prizeList: [
{pid: 3251, order: 4, code: "HW-AM115", title: "华为半入耳式耳机AM115"},
{pid: 3231, order: 3, code: "iphone-12", title: "苹果12 64G绿色"},
{pid: 3261, order: 2, code: "PMC_iphone12_bhk", title: "浦诺菲-苹果12水晶保护壳"},
{pid: 3271, order: 6, code: "PMC-18C", title: "浦诺菲_PMC-18C PD双口充电器"},
{pid: 3241, order: 5, code: "SLY_RPB-N16", title: "丝兰雅_RPB-N16移动电源"},
{pid: 3221, code: "lost", title: "离大奖就差一点点啦~"}
]

3.实现过程

3.1 布局

这里页面布局的时候要和UI沟通一个细节,就是背景图中上下两个奖品的间隔是最上面一个奖品和顶部中间间隔的两倍。如下图2



图2

同理,背景图中上下两个奖品的间隔是最下面一个奖品和底部中间间隔的两倍。如下图3



图3

最后整张背景图片如下图4



图4

这样滚动起来看上去是一张整体的图片,而不会出现偏差。三栏布局使用flex来实现,html代码如下:

<div class="session">
<div class="lottory-box">
<div class="top-fill"></div>
<div class="tiger tiger-first"></div>
<div class="tiger tiger-second center"></div>
<div class="tiger tiger-thired"></div>
<div class="bottom-fill"></div>
</div>
<img src="../assets/images/btn-lottery/btn-draw-lottery.gif" alt="" class="dray-lottery" @click="lotteryClick">
</div>

css代码如下:

.box {
background: #FFBA76;
width: 702px;
margin: 50px auto;
border-radius: 0px 0px 8px 8px;
.session {
padding-top: 22px;
.lottory-box {
position: relative;
width: 664px;
height: 341px;
margin: 0 auto;
background: no-repeat url("../assets/images/bg-lottery-box.png") center/664px 341px;
border-radius: 8px;
@include flex(center, center, nowrap, row);
.tiger-first, .tiger-second, .tiger-thired {
width: 191px;
height: 341px;
}
//背景图是同一个图片,y轴位置不同
.tiger-first {
background: url("../assets/images/img-prizelist-border.png") center 62px/191px auto;
}
.tiger-second {
background: url("../assets/images/img-prizelist-border.png") center -167px/191px auto;
}
.tiger-thired {
background: url("../assets/images/img-prizelist-border.png") center -396px/191px auto;
}
.center {
margin: 0 20px;
}
.top-fill, .bottom-fill {
position: absolute;
}
.top-fill {
top: 0;
width: 660px;
height: 49px;
background: linear-gradient(180deg, #D15000 0%, rgba(241, 92, 0, 0) 100%);
border-radius: 5px 5px 1px 1px;
}
.bottom-fill {
bottom: 0;
width: 660px;
height: 49px;
background: linear-gradient(180deg, rgba(241, 92, 0, 0) 0%, #D15000 100%);
border-radius: 1px 1px 7px 7px;
}
}
img.dray-lottery {
width: 549px;
}
}
}

注意初始状态下,tiger-first,tiger-second,tiger-thired三张背景图片的定位已近写在css里面,可以根据情况调整。最后界面效果如下图5:



图5

3.2 动画

布局有了就可以让它动起来了,首先让三张背景图匀速运动起来,最后一起停止。代码如下:

lotteryClick() {
let u = 1145 //整个背景高度
let that = this
//播放动画
jQuery(".tiger").each(function(index) {
let currNum = jQuery(this)
currNum.animate({backgroundPositionY: "+=" + (u * 3)/75 + 'rem'},
{easing: "easeInOutCirc", duration: 4000 })
})
}

变量u是整个背景图片的高度,先让背景滚动3次,然后再除以75得到先对单位rem,这个75就是上面提到的rootValue,这里用到的是'+=',也就是在原有的backgroundPositionY的基础上再加上一个相对的位移,duration:4000,让这个动画整个执行4秒钟时间。效果如下图6



图6

需求要求三张图片从左到有先后滚动,这个可以使用setTimeout(fn, time);来实现,代码如下:

//播放动画
jQuery(".tiger").each(function(index) {
let currNum = jQuery(this)
setTimeout(() => {
currNum.animate({backgroundPositionY: "+=" + (u * 3)/75 + 'rem'},
{easing: "easeInOutCirc", duration: 4000 })
}, index * 300)
})

利用jquery中each的参数index,代表当前元素的下标,乘以300,这样第一个立即执行,第二个300毫秒后执行,第三个600毫秒后执行,效果如下图7:



图6

为了使效果看起来更加逼真,可以让每个图片滚动的时间有所差异,第一个最短,最后一个最长,这样看起来效果更逼真。方法是给一个延迟参数wast,加在配置参数duration上,代码如下:

lotteryClick() {
let u = 1145 //整个背景高度
let waste = 800 //调整动画时间
//播放动画
jQuery(".tiger").each(function(index) {
let currNum = jQuery(this)
setTimeout(() => {
currNum.animate({backgroundPositionY: "+=" + (u * 3)/75 + 'rem'},
{easing: "easeInOutCirc", duration: 4000 + index * waste })
}, index * 300)
})
}

效果如下图7



图7

3.3 请求接口&再动画

动画有了,现在要开始从接口中拿数据来定位奖品了。请求接口和上面的动画一起执行,这里假定接口响应的时间一定是少于2 * 300 + 4000 + 2 * 800 = 6200ms,一般来说这个时间足够了,这段时间内动画空转。拿到结果后再播放第二个动画来固定奖品图片。代码如下:

//避免重复点击
let that = this
if (this.disabled) {
return
}
this.disabled = true
//抽奖
that.pid = -1
coc2.drawLottery({actId: actId.lottery}).then(res => {
// 临时抽奖
// res = {"code": "0","data":{"pid":3221}}
if (res.code == 0) {
let data = res.data
this.pid = data.pid
} else if (res.code == 102002) {
this.pid = 3221
} else if (res.code == 303) {
//拉起登录
pullLogin()
} else {
this.lotteryMsg = res.message
}
})

这里用一个变量pid记住奖品id,然后播放第二个动画,这时jquery动画提供了一个done方法执行动画完成之后的后续操作。代码如下:

//播放动画
jQuery(".tiger").each(function(index) {
let currNum = jQuery(this)
setTimeout(() => {
currNum.animate({backgroundPositionY: "+=" + (u * 3)/75 + 'rem'},
{easing: "easeInOutCirc", duration: 4000 + index * waste, done: function() {
snapToGrid(currNum, index)
}})
}, index * 300)
})

snapToGrid方法就是执行第二个动画了,代码如下:

//对齐奖品图片
function snapToGrid(domObj, index) {
let prizeNumber = 0
//谢谢惠顾
if ([3221, -1].includes(that.pid)) {
let result = that.numRand()
let numArr = (result + '').split('')
prizeNumber = parseInt(numArr[index])
} else {
let prize = that.prizeList.find(p => p.pid == that.pid)
prizeNumber = prize.order
}
domObj.animate({backgroundPositionY: "+=" + (prizeH * prizeNumber) / 75 + "rem"},
{easing: "linear", duration: prizeNumber * waste, done: function() {
if (index == 2) {
if (that.pid > -1) {
that.$refs.dialogPrize.popUp(that.pid)
} else {
that.$toast(that.lotteryMsg)
}
that.disabled = false
}
}
})
}

这里这里还有个逻辑,如果未中奖(谢谢惠顾),要生成三个不相等的随机数来让奖品图片固定,就是上面的that.numRand(),用它在0,1,2,3,4中随机选三个来固定奖品图片。具体方法如下:

//生成随机顺序
numRand() {
let arr = ["0", "1", "2", "3", "4"], res = ""
for (let i = 0; i < 3; i++) {
let rnd = Math.floor(Math.random() * arr.length)
res += arr[rnd]
arr.splice(rnd, 1)
}
return res
}

还有个地方要注意,一开始的时候默认显示的奖品图片是没有对齐的,在动画空转3圈结束后让然不会对齐,等接口有结果后需要对齐奖品,而prizeList变量中纪录的order是按照从上到下的次序来的,最后固定到奖品图片时不可能对准。所以在开始动画之前要将每张背景图片固定到起始的位置,代码如下:

jQuery(".tiger").css('backgroundPositionY', 0)

最后看一下整体抽奖动画效果,如下图8



图8

4.总结

jquery动画提供了丰富的功能,能灵活的控制动画参数和想要的效果,在vue中虽然也提供了动画功能,但是处理一些复杂的操作用起来不是太理想。

抽奖动画 - lao虎机抽奖的更多相关文章

  1. 原生javascript实现老.虎机抽奖点名demo源码思路解析

    想着使用原生Javascript做一个随机点名的小应用, 也可以做抽奖使用. html简单化,人名单可以通过js生成并处理. 可以非常随意的添加修改人名字. 应用想带点特效,比如老.虎机转动的特效. ...

  2. 【Vue.js游戏机实战】- Vue.js实现九宫格水果机抽奖游戏总结

    大家好!先上图看看本次案例的整体效果. 完整版实战课程附源码:[Vue.js游戏机实战]- Vue.js实现九宫格水果机抽奖 实现思路: Vue component实现九宫格水果机组件,可以嵌套到任意 ...

  3. 【Vue.js游戏机实战】- Vue.js实现老虎-机抽奖总结

    大家好!先上图看看本次案例的整体效果. 完整版实战课程附源码:[Vue.js游戏机实战]- Vue.js实现老虎-机抽奖 实现思路: Vue component实现老虎-机组件,可以嵌套到任意要使用的 ...

  4. 水果机抽奖(CocosCreator)

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321 一.前言       在前面给大家分享了大转盘的抽奖方式,这是现在游戏使用较多的一种抽奖方式,今天给大家介绍另一抽奖方式--水果 ...

  5. cocos 水果机,老Tiger虎机流水灯,博彩大转盘效果

    原(http://www.cnblogs.com/zisou/p/cocos2d-xZhuanpan.html) 博彩大转盘,转盘抽奖的小系统,这是一个很有意思的游戏模块,游戏中增加这样一些趣味的小模 ...

  6. 前端js实现九宫格模式抽奖(多宫格抽奖)

    介绍: 前端九宫格是一种常见的抽奖方式,js实现如下,掌握其原理,不论多少宫格,都可以轻松应对.(代码可复制直接运行看效果). 该案例以四宫格入门,可扩展多宫格,奖品模块的布局可自由设置. <! ...

  7. iOS 数字滚动 类似于老 - 虎- 机的效果

    效果图 具体实现代码如下 ZCWScrollNumView.h文件 #import <UIKit/UIKit.h> typedef enum { ZCWScrollNumAnimation ...

  8. 让数字变化炫酷起来,数字滚动Text组件[Unity]

    让数字滚动起来 上周我的策划又提了样需求,当玩家评分发生变动时,屏幕出现人物评分浮层UI,播放评分数字滚动动画.这类数字滚动需求非常常见,我就按一般思路,将startvalue与endvalue每隔一 ...

  9. 【Vue.js游戏机实战】- Vue.js实现大转盘抽奖总结

    大家好!先上图看看本次案例的整体效果. 实现思路: Vue component实现大转盘组件,可以嵌套到任意要使用的页面. css3 transform控制大转盘抽奖过程的动画效果. 抽奖组件内使用钩 ...

随机推荐

  1. Netty 框架学习 —— 基于 Netty 的 HTTP/HTTPS 应用程序

    通过 SSL/TLS 保护应用程序 SSL 和 TLS 安全协议层叠在其他协议之上,用以实现数据安全.为了支持 SSL/TLS,Java 提供了 javax.net.ssl 包,它的 SSLConte ...

  2. 基于Ubuntu下以Docker方式gitlab软件的部署

    基于Ubuntu下以Docker方式gitlab软件的部署 目录 基于Ubuntu下以Docker方式gitlab软件的部署 1.安装Docker Compose 1.1 下载curl 1.2 安装c ...

  3. 为什么catch了异常,但事务还是回滚了?

    前几天我发了这篇文章<我来出个题:这个事务会不会回滚?>得到了很多不错的反馈,也有不少读者通过微信.群或者邮件的方式,给了我一些关于test4的回复.其中还有直接发给我测试案例,来证明我的 ...

  4. js笔记15

    DOM2动态创建节点 1.生成节点的方法 document.createElement("div") 2.插入节点的方法 父元素.appendChild(新节点) 在父节点的子节点 ...

  5. uniapp 打包IOS 更新AppStore版本

    Hello 你好,我是大粽子. 最近随着新版本UI的发布APP也随之更新,随之而来的也就是IOS程序提审步骤,这次我详细的截图了每一个步骤,如果你正好也需要那么跟着我的节奏一步步来肯定是没问题的. 提 ...

  6. <题解>世界树

    世界树<题解> 首先我们拿到这个题之后,能想到的一定是虚树,如果想不到的话,还是重新学一遍去吧 所以我们应该怎么做呢 虚树的板子不需要我再讲一遍了吧 所以对于这个题来说,怎么根据虚树上的节 ...

  7. 9、SpringBoot整合之SpringBoot整合SpringSecurity

    SpringBoot整合SpringSecurity 一.创建项目,选择依赖 选择Spring Web.Thymeleaf即可 二.在pom文件中导入相关依赖 <!-- 导入SpringSecu ...

  8. 小程序之app.json not found

    起因 最近在部署几款小程序时,发现ext.json文件会被忽略不上传,查了一下资料发现原来是需要升级开发者工具了. 没想到升级以后,再开发项目时,就报错 app.json not found 解决方法 ...

  9. (转) PHP实现从1累加到100(1+2+….+100=)的几种思路,挺有意思的!!!

    一个经典的小学问题也是一个简单的PHP小应用,1+2+3--100=多少?使用PHP应该怎么写? 这里总结了以下几种思路: 1.普通PHPer: $sum=0;for($i=1;$i<=100; ...

  10. Docker部署Mysq集群

    1.PXC(Percona XtraDB Cluster) 速度慢 但能保证强一致性 适用于保存价值较高的数据 数据同步是双向的 在任一节点写入数据 都会同步到其他所有节点 在任何节点上都能同时读写 ...