来来来,实现一个简单的抽奖

2018/12/14 17:32
阅读数 7

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

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

逻辑

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

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

这里我们要先封装一个抽奖的对象,把抽奖本身的一些逻辑分离出来,和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);
    }

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

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

})()

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部