來來來,實現一個簡單的抽獎

一回頭, 12月中旬了。 最近項目忙,還被封閉了半個月。
爲了保持一個月1到2篇博客,月中了,就說說上次寫的抽獎吧。html

這裏講的是九宮格抽獎,其實圓盤的那種都相似。
在線demo地址
在線代碼地址git

邏輯github

  1. 點擊抽獎後立馬開始動畫效果
  2. 請求接口得到中獎結果
  3. 減慢動畫效果, 命中獎品

從上能夠看出來,其實你中獎不中獎是服務來決定的,前臺那一些絢麗的動畫,就是給你帶來快感的。app

這裏咱們要先封裝一個抽獎的對象,把抽獎自己的一些邏輯分離出來,和DOM等等不要有半毛錢關係。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

  • 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
    上次轉動時間

再額外提兩個方prototype

  • 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效果圖rest

在線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

})()
相關文章
相關標籤/搜索