文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>【项目分析】设计一个计时器的jQuery插件(4)(附赠:中秋节祝福)

【项目分析】设计一个计时器的jQuery插件(4)(附赠:中秋节祝福)

时间:2010-09-22  来源:Leepy

背景

目前团队所负责的公务员考试的项目中,需要使用到计数器的前端JS组件,具体应用可以查看页面。

你会发现这里的计时器代码有些问题。

这里使用的是

代码 this._timerId = window.setInterval(function() { 
                    $this._step(); 
                }, 1000);

//…

_step: function() { 
           if (this._pattern == 'down') 
               this._currentTime -= 1; 
           else 
               this._currentTime += 1; 
           //每秒执行一次回调函数 
           if (this._currentTime == 0 || this._currentTime > this._totalTime) { 
               this.Stop(); 
           } 
           else { 
               this._runCallBack(this._onInterval); 
           } 
       }

 

可以发现,这里在触发1秒的时候,使用的是直接增加1秒或者减少1秒的方式进行。这样是不合理的。我们可以发现我们在浏览器上选择右键,这里的计时器会被停止,当你下次再触发事件的时候,时间就不准确了。这样,只要用户点击右键,就能够把计时器给停掉。有的人说,可以屏蔽右键,但是并不是所有浏览器,都能够支持屏蔽右键,并且还有其他的方式能够使计时器停止;或者,可以使用flash来实现的计时器的功能,嗯,这样是可以的,只是我们的开发人员对于flash不是很熟悉,于是想还是自己重新设计下这个JS的计时器组件。

于是我这里采用了jQuery插件的方式来重写这个计时器组件。

 

具体分析

1. 首先先来看下最后的调用方法是什么样的:

代码 <div id="counter-1"> 
</div>

<div id="counter-2"> 
</div>

$('#counter-1').counter({ 'pattern': 'down', 'totalTime': 3600, 'onInterval': fnInterval, 'onStop': fnStop }); 
$('#counter-2').counter({ 'pattern': 'up' });

 

通过代码可以很直观的看到实现的方式,其中pattern是计时器的方式(累减或者累加),totalTime是倒计时总时间,onInterval是每跳动一次计时器,需要触发的事件,onStop是等计时器倒计时完毕后触发的事件。

 

2. 然后,来看看jquery.counter.js中的核心代码:

代码 /* 主函数 */ 
$.fn.counter = function(options) { 
    var args = Array.prototype.slice.call(arguments, 1); 

    return this.each(function() { 
        if (typeof options == 'string') { 
            $.counter['_' + options + 'Counter'].apply($.counter, [this].concat(args)); 
        } 
        else { 
            $.counter._attachCounter(this, options); 
        } 
    }); 
};

 

这里的options是Object类型的,所以调用 $.counter._attachCounter(this, options)。

接着看:

代码 /* 绑定计数器 */ 
_attachCounter: function(target, options) { 
    var inst = { options: $.extend({ 'from': new Date() }, options) }; 
    $.data(target, DATA_NAME, inst); 
    this._changeCounter(target); 
}

 

这里把inst的选项数据作为一个数据对象在客户端保存起来 $.data(target, DATA_NAME, inst);

/* 重置计数器 */ 
_changeCounter: function(target) { 
    this._addTarget(target); 
    this._updateCounter(target); 

}

 其中_addTarget是为了把目标的jQuery对象放在一个目标计时器列表_timerTargets中去维护。

代码 /* 重新显示计数器 */ 
_updateCounter: function(target) { 

    var remainTime = this._getTime(target); 
    if (remainTime) { 
        //回调函数调用 
        var inst = $.data(target, DATA_NAME); 
        if (remainTime >= 0) { 
            var time = this._getFormatTime(remainTime); 
            $(target).html(time); 

            var onInterval = this._get(inst, 'onInterval'); 
            if (onInterval) { 
                onInterval.apply(target, [remainTime]); 
            } 
        } 
        else { 
            remainTime = 0; 
            var time = this._getFormatTime(remainTime); 
            $(target).html(time); 

            var onStop = this._get(inst, 'onStop'); 
            if (onStop) { 
                onStop.apply(target, []); 
                this._removeTarget(target); 
            } 
        } 
    }

这里是前端显示的核心代码,onInterval,onStop会触发相关的事件;

通过from的起始设置的时间,来每次触发时候相减来计算剩余时间,而不是像前面那种JS组件那边,每隔一秒加(减)1。

 

3. 具体计时的是在何时触发的呢?

$.extend(Counter.prototype, { 
    /* 共享所有的timer */ 
    _timer: setInterval(function() { $.counter._updateTargets(); }, 900), 
    /* 当前激活的timer列表 */ 
    _timerTargets: [],

    …

});

 

这里每隔900毫秒会执行一次事件(可以根据您的情况来设置)

代码 var remainTime = this._getTime(target);可以获得剩余的时间;

/* 获取当前计数器的时间秒数 */ 
_getTime: function(target) { 
    var inst = $.data(target, DATA_NAME); 
    if (inst) { 
        var pattern = this._get(inst, 'pattern'); 
        if (pattern == 'down') { 
            var totalTime = this._get(inst, 'totalTime'); 
            var from = this._get(inst, 'from'); 
            var nowDate = new Date(); 
            var remainTime = parseInt((totalTime * 1000 - (nowDate.getTime() - from.getTime())) / 1000); 
            return remainTime; 
        } 
        else if (pattern == 'up') { 
            var from = this._get(inst, 'from'); 
            var nowDate = new Date(); 
            var remainTime = parseInt((nowDate.getTime() - from.getTime()) / 1000); 
            return remainTime; 
        } 
    } 
    return null; 
}

 

4. 通过getTime方法来获取剩余时间:

代码 /* 获取计时器当前时间(总秒数) */ 
$.fn.getTime = function() { 
    var args = Array.prototype.slice.call(arguments, 1); 
    if (this.length == 1) { 
        return $.counter['_getTime'].apply($.counter, [this[0]].concat(args)); 
    } 
    else if (this.length > 1) { 
        var array = []; 
        this.each(function() { 
        var time = $.counter['_getTime'].apply($.counter, [this].concat(args)); 
            if (time) { 
                array.push(time); 
            } 
        }); 
        return array; 
    } 
    return null; 
};

 

调用方式为:

$('#counter-1').getTime()

 

5. 通过string参数来实现暂停和继续的功能:

$('#btnPause').toggle(function() { 
    $(this).val('继续'); 
    $('.counter').counter('pause'); 
}, function() { 
    $(this).val('暂停'); 
    $('.counter').counter('resume'); 

);

 

 

其他的请看完整代码:

代码 /*
* 计数器jQuery插件
* Copyright: Leepy
* Update: 2010-09-22
* Home:   http://www.cnblogs.com/liping13599168/
*/

(function($) {

    function Counter() {
        /* 计数器默认配置 */
        this._defaults = {
            pattern: 'down',    // 可选择参数:'up', 'down';默认方式为减计数
            totalTime: 3600,    // 总共需要多少时间,单位为秒
            until: null,        // 默认直到日期的配置
            onInterval: null,   // 间隔时间回调函数
            onStop: null        // 结束时回调函数
        }
    }

    var DATA_NAME = 'data_counter';

    $.extend(Counter.prototype, {
        /* 共享所有的timer */
        _timer: setInterval(function() { $.counter._updateTargets(); }, 900),
        /* 当前激活的timer列表 */
        _timerTargets: [],
        /* 更新每一个绑定的目标计数器 */
        _updateTargets: function() {
            for (var i = 0, length = this._timerTargets.length; i < length; i++) {
                this._updateCounter(this._timerTargets[i]);
            }
        },
        /* 绑定计数器 */
        _attachCounter: function(target, options) {
            var inst = { options: $.extend({ 'from': new Date() }, options) };
            $.data(target, DATA_NAME, inst);
            this._changeCounter(target);
        },
        /* 重置计数器 */
        _changeCounter: function(target) {
            this._addTarget(target);
            this._updateCounter(target);

        },
        /* 重新显示计数器 */
        _updateCounter: function(target) {

            var remainTime = this._getTime(target);
            if (remainTime) {
                //回调函数调用
                var inst = $.data(target, DATA_NAME);
                if (remainTime >= 0) {
                    var time = this._getFormatTime(remainTime);
                    $(target).html(time);

                    var onInterval = this._get(inst, 'onInterval');
                    if (onInterval) {
                        onInterval.apply(target, [remainTime]);
                    }
                }
                else {
                    remainTime = 0;
                    var time = this._getFormatTime(remainTime);
                    $(target).html(time);

                    var onStop = this._get(inst, 'onStop');
                    if (onStop) {
                        onStop.apply(target, []);
                        this._removeTarget(target);
                    }
                }
            }

        },
        /* 暂停计数器 */
        _pauseCounter: function(target) {
            var inst = $.data(target, DATA_NAME);
            if (inst) {
                var pauseTime = new Date();
                $.extend(inst.options, { 'pauseTime': pauseTime });
                $.data(target, DATA_NAME, inst);
                this._removeTarget(target);
            }
        },
        /* 重新启动计数器 */
        _resumeCounter: function(target) {
            var inst = $.data(target, DATA_NAME);
            if (inst) {
                var nowDate = new Date();
                var pauseTime = this._get(inst, 'pauseTime');
                var from = this._get(inst, 'from');
                if (pauseTime) {
                    var fromTime = new Date(from.getTime() + (nowDate.getTime() - pauseTime.getTime()));
                    $.extend(inst.options, { 'from': fromTime });
                    $.data(target, DATA_NAME, inst);
                    this._changeCounter(target);
                }
            }
        },
        /* 获取当前计数器的时间秒数 */
        _getTime: function(target) {
            var inst = $.data(target, DATA_NAME);
            if (inst) {
                var pattern = this._get(inst, 'pattern');
                if (pattern == 'down') {
                    var totalTime = this._get(inst, 'totalTime');
                    var from = this._get(inst, 'from');
                    var nowDate = new Date();
                    var remainTime = parseInt((totalTime * 1000 - (nowDate.getTime() - from.getTime())) / 1000);
                    return remainTime;
                }
                else if (pattern == 'up') {
                    var from = this._get(inst, 'from');
                    var nowDate = new Date();
                    var remainTime = parseInt((nowDate.getTime() - from.getTime()) / 1000);
                    return remainTime;
                }
            }
            return null;
        },
        /* 获取格式化的时间 */
        _getFormatTime: function(remainTime) {
            var hour = parseInt(remainTime / 3600);
            var min = parseInt(remainTime / 60) % 60;
            var second = remainTime % 60;
            var time = this._stringFormat('{0}:{1}:{2}',
                    (hour < 10 ? '0' + hour : hour),
                    (min < 10 ? '0' + min : min),
                    (second < 10 ? '0' + second : second));
            return time;
        },
        /* 从配置中获取指定名称的值 */
        _get: function(inst, name) {
            return inst.options[name] != null ? inst.options[name] : $.counter._defaults[name];
        },
        /* 添加到目标计数器列表中 */
        _addTarget: function(target) {
            if (!this._hasTarget(target)) this._timerTargets.push(target);
        },
        /* 是否已经包含在目标计数器列表中 */
        _hasTarget: function(target) {
            return ($.inArray(target, this._timerTargets) > -1);
        },
        /* 移除指定目标计数器 */
        _removeTarget: function(target) {
            this._timerTargets = $.map(this._timerTargets, function(o) { return (o == target ? null : o); });
        },
        //string格式化构造器
        _stringFormat: function(str) {
            var args = arguments;
            return str.replace(/\{(\d+)\}/g,
                function(m, i) {
                    return args[parseInt(i) + 1];
                });
        }
    });

    /* 主函数 */
    $.fn.counter = function(options) {
        var args = Array.prototype.slice.call(arguments, 1);

        return this.each(function() {
            if (typeof options == 'string') {
                $.counter['_' + options + 'Counter'].apply($.counter, [this].concat(args));
            }
            else {
                $.counter._attachCounter(this, options);
            }
        });
    };
    /* 获取计时器当前时间(总秒数) */
    $.fn.getTime = function() {
        var args = Array.prototype.slice.call(arguments, 1);
        if (this.length == 1) {
            return $.counter['_getTime'].apply($.counter, [this[0]].concat(args));
        }
        else if (this.length > 1) {
            var array = [];
            this.each(function() {
            var time = $.counter['_getTime'].apply($.counter, [this].concat(args));
                if (time) {
                    array.push(time);
                }
            });
            return array;
        }
        return null;
    };

    $.counter = new Counter();

})(jQuery);
 

 

附上源代码下载:CounterJSLab.rar

 

最后啦,今天是中秋节,引用一下一位同事的祝福词咯!

忍养安,乐养寿,爱养福,善养运,佛养心,道养行,学养德,诚养誉,礼养谊,动养身,天养地,古养今,问候养情谊! 祝各位博客园的园友中秋快乐!

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载