来来来,实现一个简单的抽奖
2019-08-30

一回头, 12月中旬了。 最近项目忙,还被封闭了半个月。为了保持一个月1到2篇博客,月中了,就说说上次写的抽奖吧。

这里讲的是九宫格抽奖,其实圆盘的那种都类似。在线demo地址在线代码地址

逻辑

    点击抽奖后立马开始动画效果请求接口获得中奖结果减慢动画效果, 命中奖品

从上可以看出来,其实你中奖不中奖是服务来决定的,前台那一些绚丽的动画,就是给你带来快感的。

这里我们要先封装一个抽奖的对象,把抽奖本身的一些逻辑分离出来,和DOM等等不要有半毛钱关系。

定义Lottery对外方法:

start: 开始stop: 结束setPrize: 设置奖项对外公布事件onStart: 当开始的时候onUpdate: 当旋转一步onEnded: 当结束onError

Lottery初始化参数

startIndex: 0初始位置pits: 8当前位置interval: 100初始间隔rate: 1.5下一次时间间隔系数cycle: 20动基本次数:即至少需要转动多少次再进入抽奖环节getInterval: null自定义旋转间隔函数,定义后会使用该函数的返回值intervalonStart: null开始后的回调函数onUpdate: null旋转一次的回调函数onEnded: null结束后的回调函数onError: null异常的回调函数, 比如转动次数已经达到设定值, 但是没有设置奖项

内部参数

this.originOptions = options传入的配置项this.options = $.extend({}, defaultOption, options)合并后的配置项this.ticketId = null定时器idthis.prizeIndexes = null奖项索引位置this.times = 0已经转动的次数this.index = 0当前所在的位置this.animatingResult = false是否在模拟结果this.cycle = this.options.cycle实际的转动基本次数, 大于开始中奖this.processing = false是否进行中this.lastTime = null上次转动时间

再额外提两个方

emit这个类似events的emit, 触发订阅事件

Lottery.prototype.emit = function (type) { var params = slice.call(arguments); var restParams = params.slice(1); var type = params[0]; var method = this["on" + type]; if ($.isFunction(method)) { method.apply(this, restParams); } }innerStart和next, 这里实现只要调用next,就会进入下一次计时器作业

Lottery.prototype.innerStart = function (cb) { var that = this; var next = function () { that.next(function () { cb && cb(next); }) } next() } Lottery.prototype.next = function (cb) { var interval = this.getInterval(); this.ticketId = setTimeout(cb, interval); }

到这里其实,大家都基本明白了怎么实现了吧。

在线demo地址在线代码地址

附上Lottery源码

(function () { var defaultOption = { startIndex: 0, // 初始位置 pits: 8, // 当前位置 interval: 100, // 初始间隔 rate: 1.5, // 系数 cycle: 20, //转动基本次数:即至少需要转动多少次再进入抽奖环节 getInterval: null // 自定义旋转间隔函数 //onStart: null, // 当开始 //onUpdate: null, // 旋转一次 //onEnded: null, // 结束 //onError: null // 异常, 比如转动次数已经达到设定值, 但是没有设置奖项 }; var slice = Array.prototype.slice; function Lottery(options) { this.originOptions = options; this.options = $.extend({}, defaultOption, options); // 定时器Id this.ticketId = null; // 奖项 this.prizeIndexes = null; // 转动次数 this.times = 0; // 当前位置 this.index = 0; // 模拟结果 this.animatingResult = false; // 实际的转动基本次数, 大于开始中奖 this.cycle = this.options.cycle; // 进行中 this.processing = false; // 上次转动时间 this.lastTime = null; } Lottery.prototype.start = function () { if (this.processing) { return } this.processing = true; // 增加随机数 this.cycle = this.options.cycle + Math.floor(Math.random() * 10); this.emit("Start", this, this.index, this.cycle); this.lastTime = Date.now(); var that = this; this.innerStart(function (next) { if (that.animatingResult) { that.times++; } that.index = (that.index + 1) % that.options.pits; var continu = that.judge(); if (!continu) { that.stop(); return } that.printInfo(); that.emit("Update", that, that.index, that.times); next(); }) } Lottery.prototype.judge = function () { var cycle = this.cycle; var times = this.times; // 到达旋转次数 if (times > cycle) { // 没有设置奖项 if (!$.isArray(this.prizeIndexes)) { this.emit("Error", this, 404, "未设置奖项"); return false; } if (this.prizeIndexes.indexOf(this.index) >= 0) { this.emit("Ended", this, this.index, this.prizeIndexes); return false; } } return true; } Lottery.prototype.emit = function (type) { var params = slice.call(arguments); var restParams = params.slice(1); var type = params[0]; var method = this["on" + type]; if ($.isFunction(method)) { method.apply(this, restParams); } } Lottery.prototype.stop = function () { this.clearJob(); this.animatingResult = false; this.ticketId = null; this.prizeIndexes = null; this.times = 0; this.processing = false; } Lottery.prototype.getInterval = function () { const getIntervalFn = this.options; if ($.isFunction(getIntervalFn)) { return getIntervalFn(this, this.index, this.times, this.cycle); } else { return Math.floor(this.options.interval * Math.pow(this.options.rate, this.times / 10)); } } Lottery.prototype.clearJob = function () { clearTimeout(this.ticketId); } Lottery.prototype.innerStart = function (cb) { var that = this; var next = function () { that.next(function () { cb && cb(next); }) } next() } Lottery.prototype.next = function (cb) { var interval = this.getInterval(); this.ticketId = setTimeout(cb, interval); } Lottery.prototype.reset = function () { this.stop(); this.options = $.extends({}, defaultOption, this.originOptions); this.index = 0; } Lottery.prototype.setPrize = function (prizeIndexes) { if (this.animatingResult) { return } this.prizeIndexes = prizeIndexes; // 设置值后, 开始模拟中奖 this.animatingResult = true } Lottery.prototype.printInfo = function () { var now = Date.now(); console.log("index:", this.index, "times:", this.times, "cycle:", this.cycle, "interval:", now - this.lastTime); this.lastTime = now; } window.Lottery = Lottery})()