一回頭, 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
自定義旋轉間隔函數,定義后會使用該函數的返回值interval - onStart: null
開始后的回調函數 - onUpdate: null
旋轉一次的回調函數 - onEnded: null
結束后的回調函數 - onError: null
異常的回調函數, 比如轉動次數已經達到設定值, 但是沒有設置獎項
內部參數
- this.originOptions = options
傳入的配置項 - this.options = $.extend({}, defaultOption, options)
合並后的配置項 - this.ticketId = null
定時器id - this.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);
}
到這里其實,大家都基本明白了怎么實現了吧。
附上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
})()