我的第一个jQuery插件。需要帮助格式化并了解其工作原理

时间:2011-02-01 13:24:46

标签: javascript jquery plugins

我今天写了第一个插件:一个简单的工具,可以使元素中的数字向上计数。 它工作得很好,但是我按照例子和一些反复试验来构建它,所以我不能说我理解它是如何完全运作的。

我不明白:

a)我应该如何包含secondsToTime()函数之类的便捷函数(假设我需要它在一个函数中 - 我知道在这个例子中它没有。)为什么它在这里工作。每个街区?

b)我声明的变量(_this, seconds, interval)如何作用域?每个元素都保持同步。

c)这个插件可以更好地构建吗?

代码:

$(document).ready(function(){
  $('.ticker').countup();
});

(function($) {   
  $.fn.countup = function() {
    return this.each(function(){
      var _this = this,
      seconds = parseInt($(this).text()),
      interval = setInterval(updateTicker, 1000 );
      updateTicker();
      function updateTicker(){
        seconds += 1;
        time = secondsToTime(seconds);
        outputtime = time.h + ":" + ((time.m <= 9) ? '0' + time.m : time.m) + ":" + ((time.s <= 9) ? '0' + time.s : time.s)
        $(_this).text(outputtime);
      }   
      function secondsToTime(secs){
        var hours = Math.floor(secs / (60 * 60));
        var divisor_for_minutes = secs % (60 * 60);
        var minutes = Math.floor(divisor_for_minutes / 60);
        var divisor_for_seconds = divisor_for_minutes % 60; 
        var seconds = Math.ceil(divisor_for_seconds);
        var obj = { 
          "h": hours,
          "m": minutes,
          "s": seconds
        };  
        return obj;
      }   
    }); 
  };  
})(jQuery); 

感谢您的反馈。

2 个答案:

答案 0 :(得分:5)

  

a)我应该如何包括像secondsToTime()函数

这样的便利函数

我会在(function($) { ... })(jQuery);函数中将其移出一个级别,因为不必为每个元素重新创建它。

  

a)...为什么它在这个块中起作用?

因为可以从在相同范围的范围内定义的代码或从嵌套范围访问函数。

  

b)我声明的变量(_thissecondsinterval)作用域是怎样的?

它们都是针对您传入this.each的函数的每个调用所特有的。更具体地说:调用函数时,会创建调用的执行上下文。该执行上下文有一个变量对象,它包含在被调用的函数内声明的变量,函数参数和函数(所有函数都特定于函数调用等等)每次都创建)。您的updateTicker函数(为每个调用创建)是对该变量对象的闭包,因此对这些变量有持久的引用。 (更多:Closures are not complicated。)

  

c)这个插件可以更好地构建吗?

  1. 见上文(a)。
  2. 我可能会将我的插件函数设为命名函数而不是匿名函数。 (更多:Anonymouses anonymous)你已经拥有了你的包装函数(我在上面的(a)中提到的那个),所以它不会花费你任何东西,但是当函数实际上有名字时它会使调试更容易。
  3. 我可能只为this创建一次jQuery对象然后重复使用它,而不是在开始时再进行两次,然后每次运行updateTicker时再次使用它。例如,使var _this = this, =&gt; var _this = $(this),并在下一行和_this.text内使用updateTicker
  4. 通过提供第二个参数强制基数parseInt通常是一个好主意(否则,前导零可能会发生奇怪的事情)。
  5. 您可以考虑仅使用一个间隔计时器来更新所有元素,而不是每个元素的间隔。
  6. 我想添加一种方法来停止更新。
  7. 请注意,计时器根本不准确,因此您的倒计时可能会有所不同。您可以考虑抓住开始时间并计算它实际存在的时间,而不是递减seconds值。
  8. 这是第一次通过上面的#1 - #4,让其他人继续执行:

    (function($) {   
    
      $.fn.countup = MyNiftyPlugin_countup;               // #2
    
      function MyNiftyPlugin_countup() {                  // #2 cont'd
        return this.each(function(){
          var _this = $(this),                            // #3
              seconds = parseInt(_this.text(), 10),       // #3 cont'd, #4
              interval = setInterval(updateTicker, 1000 );
    
          updateTicker();
    
          function updateTicker(){
            seconds += 1;
            time = secondsToTime(seconds);
            outputtime = time.h + ":" + ((time.m <= 9) ? '0' + time.m : time.m) + ":" + ((time.s <= 9) ? '0' + time.s : time.s)
            _this.text(outputtime);                       // #3 cont'd
          }   
        }); 
      }
    
      function secondsToTime(secs){                       // #1 (moving this out a level)
        var hours = Math.floor(secs / (60 * 60));
        var divisor_for_minutes = secs % (60 * 60);
        var minutes = Math.floor(divisor_for_minutes / 60);
        var divisor_for_seconds = divisor_for_minutes % 60; 
        var seconds = Math.ceil(divisor_for_seconds);
        var obj = { 
          "h": hours,
          "m": minutes,
          "s": seconds
        };  
        return obj;
      }   
    })(jQuery); 
    

答案 1 :(得分:0)

改进代码示例@ T.JCrowder给出了。

以下是循环外的间隔,只运行一次。我们将时间作为整数存储在数据中,因此我们只需要parseInt一次。获取toTime函数以返回格式化的字符串。以及其他一些小改进。

(function($) {   

    $.fn.countup = MyNiftyPlugin_countup;

    function MyNiftyPlugin_countup() {
        var that = this;
        function updateTicker(){
            that.each(updateNode);
        }      
        function updateNode() {
            var $this = $(this); // cache
            var seconds = $this.data("time") + 1; // get time from $.data
            $this.data("time", seconds);
            //var seconds = Date.now() // alternative get accurate time right _now_
            var time = secondsToTime(seconds)[1]; // get string from tuple
            $this.text(time).data("time", seconds);
        }
        setInterval(updateTicker, 1000);
        updateTicker();

        return this.each(function(){
            var $this = $(this); // cache
            $this.data("time", parseInt($this.text(), 10);
        }); 
    }

    function secondsToTime(secs){
        var hours = Math.floor(secs / (60 * 60));
        var divisor_for_minutes = secs % (60 * 60);
        var minutes = Math.floor(divisor_for_minutes / 60);
        var divisor_for_seconds = divisor_for_minutes % 60; 
        var seconds = Math.ceil(divisor_for_seconds);
        var time = { 
          "h": hours,
          "m": minutes,
          "s": seconds
        };  
        var outputtime = time.h + ":" + ((time.m <= 9) ? '0' + time.m : time.m) + ":" + ((time.s <= 9) ? '0' + time.s : time.s)
        return [time, outputtime];
    }   
})(jQuery);