Skip to content

Latest commit

 

History

History
376 lines (309 loc) · 14.3 KB

09.md

File metadata and controls

376 lines (309 loc) · 14.3 KB

八、插件

在构建插件时使用$别名

当编写 jQuery 插件时,应该实现与常规的旧 jQuery 代码相同的冲突预防例程。考虑到这一点,所有插件都应该包含在私有范围内,在这个范围内$别名可以被使用,而不用担心冲突或令人惊讶的结果。

下面的编码结构应该看起来很熟悉,因为它在本书的几乎每个代码示例中都有使用,并在第 1 章中进行了解释。

样本:sample82.html

<!DOCTYPE html>
<html lang="en">
<body>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script> 
alert(jQuery(document).jquery);
        // Don't use $ here.
It is not reliable.  
        (function ($) {
            //
Can use $ without fear of conflicts.      
            alert($(document).jquery);
        })(jQuery);  </script>
</body>
</html>

新插件附加到jQuery.fn对象成为 jQuery 方法

新插件被附加到jQuery.fn对象,因为这是jQuery.prototype的快捷方式或别名。在下面的代码示例中,我们将计数插件添加到jQuery.fn对象中。通过这样做,我们创建了自己的自定义 jQuery 方法,可以在一组包装好的 DOM 元素上使用。

基本上,附加在jQuery.fn上的插件允许我们创建自己的自定义方法,类似于在应用编程接口中找到的任何方法。这是因为当我们将插件函数附加到jQuery.fn时,我们的函数包含在原型链中—$.fn.count = function(){}—用于使用 jQuery 函数创建的 jQuery 对象。如果这让你大吃一惊,请记住,在jQuery.fn中添加一个函数意味着插件函数中的关键字this将引用 jQuery 对象本身。

样本:sample83.html

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="counter1"></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>  (function ($) {
$.fn.count = function () {
      var $this = $(this); //
"this" is the jQuery object.     
      $this.text('0'); //
Sets the counter start number to zero.     
      var myInterval =
window.setInterval(function () {
          // Interval for
counting.         
          var currentCount =
parseFloat($this.text()); var newCount = currentCount + 1; $this.text(newCount + '');
      }, 1000);
  };
  })(jQuery); jQuery('#counter1').count();  </script>
</body>
</html>

注意事项:

通过向 jQuery.fn 对象添加一个插件,我们实际上是说我们的插件想要使用 jQuery 函数来选择一个上下文(DOM 元素)。如果你的插件不需要特定的上下文(换句话说,一组 DOM 元素)来操作,你可能不需要把这个插件附加到 $.fn 上。将其作为实用函数添加到 jQuery 名称空间中可能更有意义。

在一个插件里面,this是对当前 jQuery 对象的引用

当您将插件附加到jQuery.fn对象时,附加插件函数内部使用的关键字this将引用当前的 jQuery 对象。

样本:sample84.html

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="counter1"></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>  (function ($) {
$.fn.count = function () {
      // "this" is
equal to jQuery('#counter1').     
      alert(this); //
Alerts jQuery object.     
      alert(this[0]); //
Alerts div element.      
      alert(this[0].id); //
Alerts "counter1". 
  };
  })(jQuery); jQuery('#counter1').count();  </script>
</body>
</html>

关键是你要弄清楚关键词this在插件函数中到底指的是什么。

使用 each()迭代 jQuery 对象,并使用this关键字提供对对象中每个元素的引用

使用each(),我们可以为我们的插件创建一个隐式迭代。这意味着如果包装器集合包含多个元素,我们的插件方法将应用于包装器集合中的每个元素。

为此,我们使用 jQuery 实用程序each()函数,这是一个通用的对象和数组迭代器,基本上简化了循环。在下面的代码示例中,我们使用函数迭代 jQuery 对象本身。在传递给each()的函数内部,关键字this将引用 jQuery 包装器集中的元素。

样本:sample85.html

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="counter1"></div>
    <div id="counter2"></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>   (function ($) {
       $.fn.count = function () {
           this.each(function () {
               //
"this" is the current jQuery object.             
               var $this = $(this);
               $this.text('0'); //
Sets the counter start number.             
               var myInterval =
window.setInterval(function () {
                   //
Interval for counting.                 
                   var currentCount =
parseFloat($this.text()); var newCount = currentCount + 1; $this.text(newCount + '');
               }, 1000);
           });
       };

 })(jQuery); jQuery('#counter1,
#counter2').count();  </script>
</body>
</html>

如果你想让一个插件使用隐式迭代,使用each()函数是至关重要的。

插件返回 jQuery 对象,因此 jQuery 方法或其他插件在使用插件后可以被链接

通常,大多数插件会返回 jQuery 对象本身,这样插件就不会中断链接。换句话说,如果一个插件不特别需要返回值,它应该继续这个链,这样附加的方法就可以应用到包装器集。在下面的代码中,我们用return this;语句返回 jQuery 对象,这样链接就不会中断。请注意,在我调用count()插件后,我正在链接parent()append()方法。

样本:sample86.html

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="counter1"></div>
    <div id="counter2"></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>   (function ($) {
$.fn.count = function () {
       return this.each(function () {
           //
Return the jQuery object, or "this" after each()             
           var $this = $(this);
           $this.text('0');
           var myInterval =
window.setInterval(function () { var currentCount =
parseFloat($this.text()); var newCount = currentCount + 1; $this.text(newCount + ''); }, 1000);
       });
   };
   })(jQuery); jQuery('#counter1,
#counter2').count().parent() // Chaining continues because jQuery object is
returned.     
       .append('<p>Chaining
still works!</p>');   </script>
</body>
</html>

注意事项:

通过简单地不返回 jQuery 对象,可以使插件成为一个破坏性的方法。

默认插件选项

插件通常包含默认选项,作为插件逻辑的基线默认配置。这些选项在插件被调用时使用。在下面的代码中,我正在创建一个包含单个属性(startCount)和值(0)的defaultOptions对象。该对象存储在计数功能$.fn.count.defaultOptions上。我们这样做是为了在插件之外配置选项。

样本:sample87.html

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="counter1"></div>
    <div id="counter2"></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>   (function ($) {
$.fn.count = function () {
       return this.each(function () {
           var $this = $(this);             //
Sets the counter start number to zero.             

$this.text($.fn.count.defaultOptions.startCount + '');
           var myInterval =
window.setInterval(function () { var currentCount =
parseFloat($this.text()); var newCount = currentCount + 1; $this.text(newCount + ''); }, 1000);
       });
   }; $.fn.count.defaultOptions = {
startCount: 100 };
   })(jQuery); jQuery('#counter1,
#counter2').count();    </script>
</body>
</html>

自定义插件选项

通常,默认插件选项可以被自定义选项覆盖。在下面的代码中,我传入一个customOptions对象作为插件函数的参数。该对象与defaultOptions对象组合,创建一个单独的options对象。我们使用 jQuery 实用程序方法extend()将多个对象组合成一个对象。extend()方法为用新属性覆盖对象提供了完美的工具。有了这些代码,插件现在可以在调用时进行定制。在这个例子中,我们向count插件传递一个自定义数字(500)作为计数的起点。此自定义选项会覆盖默认选项(0)。

样本:sample88.html

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="counter1"></div>
    <div id="counter2"></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>   (function ($) {
       $.fn.count = function (customOptions)
{
           //
Create new option, extend object with defaultOptoins and customOptions.        
           var options =
$.extend({}, $.fn.count.defaultOptions, customOptions);
           return this.each(function () {
               var $this = $(this); //
Sets the counter start number to the default option value             
               // or
to a custom option value if it is passed to the plugin.             

$this.text(options.startCount + '');
               var myInterval =
window.setInterval(function () { var currentCount =
parseFloat($this.text()); var newCount = currentCount + 1; $this.text(newCount + ''); }, 1000);
           });
       }; $.fn.count.defaultOptions = {
startCount: 100 };
   })(jQuery);  // Passing
a custom option overrides default. 
        jQuery('#counter1,
#counter2').count({ startCount: 500 });

    </script>
</body>
</html>

覆盖默认选项而不改变原始插件代码

因为默认选项可以从插件外部访问,所以可以在调用插件之前重置默认选项。当你想在不改变插件代码本身的情况下定义自己的选项时,这可能会很方便。这样做可以简化插件调用,因为从某种意义上来说,您可以根据自己的喜好全局设置插件,而无需分叉原始插件代码本身。

样本:sample89.html

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="counter1"></div>
    <div id="counter2"></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>   (function ($) {
       $.fn.count = function (customOptions)
{
           var options =
$.extend({}, $.fn.count.defaultOptions, customOptions);
           return this.each(function () {
               var $this = $(this);
$this.text(options.startCount + '');
               var myInterval =
window.setInterval(function () { var currentCount =
parseFloat($this.text()); var newCount = currentCount + 1; $this.text(newCount + ''); }, 1000);
           });
       }; $.fn.count.defaultOptions = {
startCount: 100 };
   })(jQuery);  //
Overwrite default options. 

jQuery.fn.count.defaultOptions.startCount = 200; jQuery('#counter1').count(); //
Will use startCount: 200, instead of startCount:0 
        jQuery('#counter2').count({
startCount: 500 }); // Will overwrite any default values.     </script>
</body>
</html>

动态创建元素,以编程方式调用插件

根据插件的性质,插件的正常调用(通过 DOM 元素和事件)以及编程调用都是至关重要的。考虑一个对话插件。有时会根据用户事件打开模式/对话框。其他时候,需要根据环境或系统事件打开一个对话框。在这些情况下,您仍然可以通过动态创建一个元素来调用插件,而无需 DOM 中的任何元素。在下面的代码中,我通过首先创建一个元素来调用我的插件,从而在页面加载时调用dialog()插件。

样本:sample90.html

<!DOCTYPE html>
<html lang="en">
<body>
    <a href="#" title="Hi">dialog, say hi</a> <a href="#" title="Bye">dialog, say
    bye</a>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>   (function ($) {
       $.fn.dialog = function (options) { var text = this.attr('title') || this.text();
alert(text); };
   })(jQuery);
        jQuery('a').click(function () { //
Invoked by user event      
            $(this).dialog(); return false;
        });
        $(window).load(function () {     //
Create DOM element to invoke the plugin     
            jQuery("<a></a>").attr('title', 'I
say hi when invoked!').dialog(); // Run immediately. 
        });  </script>
</body>
</html>

显然,根据插件的选项、复杂性和功能,这种模式可能会有很多变化。这里的要点是,插件可以通过现有的 DOM 元素调用,也可以通过那些动态创建的元素调用。

提供回调和传递上下文

创作 jQuery 插件时,最好提供 回调函数作为选项,并在回调被调用时将这些函数传递给this的上下文。这为包装件组中的元素提供了附加处理的载体。在下面的代码中,我们将一个自定义选项传递给outAndInFade()插件方法,该方法是一个函数,应该在动画完成后调用。回调函数在被调用时被传递this的值。这允许我们在我们定义的函数中使用this值。当回调函数被调用时,关键字this将引用包装器集中包含的一个 DOM 元素。

样本:sample91.html

<!DOCTYPE html>
<html lang="en">
<body>
    <div>Out And In Fade</div>
    <div>Out And In Fade</div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>   (function ($) {
$.fn.outAndInFade = function (customOptions)
{
       var options =
$.extend({}, $.fn.outAndInFade.defaultOptions, customOptions || {});
       return this.each(function () {
           $(this).fadeOut().fadeIn('normal', function () { //
Callback for fadeIn()                 
               //
Call complete() function, pass it "this".                
               if
($.isFunction(options.complete)) {

options.complete.apply(this);
               }
           });
       });
   };
       $.fn.outAndInFade.defaultOptions
= {
           complete: null // No
default function.     
       };
   })(jQuery); jQuery('div').outAndInFade({
       // Change
background-color of the element being animated on complete.     
       // Note:
"this" will refer to the DOM element in the wrapper set.     
       complete: function () { $(this).css('background', '#ff9'); }

  });  </script>
</body>
</html>