jquery扩展以及jquery ui插件开发

  1. 在jquery命名空间添加全局函数,与普通类添加全局函数一样,定义一个立即调用函数表达式,接受jQuery作为参数并将参数命名为$保证在jQuery.noConflict()调用的情况下也能在内部使用$
     1 (function ($) {
     2   $.sum = function (array)
     3   {
     4     var total = 0;
     5     $.each(array, function (index, value) {
     6       value = parseFloat(value) || 0;
     7       total += value;
     8     });
     9     return total;
    10   }; // end sum()
    11   
    12   $.average = function (array)
    13   {
    14     if ($.siArray(array))
    15     {
    16       return $.sum(array) / array.length;
    17     } // end if
    18     return "";
    19   }; // end average()
    20 }(jQuery));
    21 
    22 var data = [3, 4, 3, 4, 3, 4, 3, 4];
    23 console.log("sum: " + $.sum(data)); // 28
    24 console.log("avreage: " + $.average(data)); // 3.5
  2. 为jQuery对象添加方法,与普通类添加对象方法一样,
    1. 普通类通过默认为prototype添加方法,jQuery的prototype起了个简单的名字:fn,
    2. 函数调用上下文this为当前调用该方法的jQuery对象,
    3. 为适当方法返回this可支持链式调用
    4. 方法采用对象式传递更加方便
    5. 为方法设置可配置默认参数
    6. 下面是一个例子,用来说明基本思路,功能实现方法不推荐用于实际开发
       1 (function ($) {
       2   $.fn.shadow = function (opts)
       3   {
       4     var options = $.extend({}, $.fn.shadow.defaults, opts);
       5     return this.each(function () {
       6       var $originalelement = $(this);
       7       for (var i = 0; i < options.copies; ++i)
       8       {
       9         var offset = options.copyOffset(i);
      10         $originalElement.clone()
      11           .css({
      12             position: "absolute",
      13             left: $originalElement.offset().left + offset.x,
      14             top: $originalElement.offset().top + offset.y,
      15             margin: 0,
      16             zIndex: -1,
      17             opacity: options.opacity
      18           }).appendTo("body");
      19       } // end for
      20     }); // end each()
      21   }; // end shadow()
      22   
      23   // define comfigurable defaults for shadow
      24   $.fn.shadow.defaults = {
      25     copies: 5,
      26     opacity: 0.1,
      27     copyOffset: function (index)
      28     {
      29       return {x: index, y: index};
      30     } // end copyOffset()
      31   }; // end defaults
      32 }(jQuery));
      33 
      34 
      35 // test case
      36 $.fn.shadow.defaults.copies = 10;
      37 $("h1").shadow({
      38   copyOffset: function (index)
      39   {
      40     return {x: -index, y: index};
      41   } // end copyOffset()
      42 });
  3. jquery ui插件开发比扩展jquery稍微复杂,但是jQuery UI包含了一个控件工厂$.widget()帮我们做了很多工作,通过这个工厂方法可以保证我们的代码遵守API标准,也就方便用户使用
    1. 插件具有stateful特性,这样可以通过检查状态,修改状态完成各种需求
    2. 用户选项和可配置默认选项自动归并
    3. 多个插件方法可以通过传递字符串为方法调用简单jQuery方法实现无缝连接,
    4. 自定义事件监控可以访问控件实例的数据
  4. jQuery UI插件通过调用$.widget()创建。这个函数接受两个参数
    1. 第一个是一个字符串,这是一个包含了命名空间的插件名如"ljq.tooltip"这样我们的插件就可以通过在jQuery对象上调用.tooltip()来安装了
    2. 第二个参数是一个对象,其属性包含一些widget()预定义属性,根据约定完成空间初始化、销毁等
  5. 为第二个参数设置_create,这是在插件初始化时控件工厂自动调用的函数:
     1 (function ($) {
     2   $.widget("ljq.tooltip", {
     3     _create: function ()
     4     {
     5       this._tooltipDiv = $("<div></div>")
     6         .addClass("ljq-tooltip-text ui-widget "
     7           + "ui-state-highlight ui-corner-all")
     8         .hide().appendTo("body");
     9       this.element.addClass("ljq-tooltip-trigger")
    10         .on("mouseenter.ljq-tooltip", $.proxy(this._open, this))
    11         .on("mouseleave.ljq-tooltip", $.proxy(this._close, this));
    12     }, // end _create()
    13     _open: function ()
    14     {
    15       var elementOffset = this.element.offset();
    16       this._tooltipDiv.css({
    17         position: "absolute",
    18         left: elementOffset.left,
    19         top: elementOffset.top + this.element.height()
    20       }).text(this.element.data("tooltip-text"));
    21       this._tooltipDiv.show();
    22     }, // end _open()
    23     _close: function ()
    24     {
    25       this._tooltipDiv.hide();
    26     } // end _close()
    27   }); // end widget.toolip()
    28 }(jQuery));
    1. 其中_create()调用上下文this为当前创建的控件实例,可以给它添加所需的属性,例如:this._tooltipDiv
    2. 控件实例包含一些有用的属性: this.element是创建空间的jQuery对象
    3. 通过为this.element绑定mouseenter和mouseleave事件监听器,控制tooltip的出现
  6. 销毁控件,上面的方法创建了一个jQuery新方法,在jQuery对象上调用即可创建tooltip,如$("a").tooltip(),同样也可以通过传入一个字符串作为参数,用于指定需要调用的方法,其中内建的destroy方法会将控件取消,.tooltip("destroy")可以调用,控件工厂可以帮我们做大多数工作,但是如果我们像tooltip一样创建的新的dom节点,我们必须自定义方法来完成清理
     1 (function ($) {
     2   $.widget("ljq.tooltip", {
     3     _create: function ()
     4     {
     5       this._tooltipDiv = $("<div></div>")
     6         .addClass("ljq-tooltip-text ui-widget "
     7           + "ui-state-highlight ui-corner-all")
     8         .hide().appendTo("body");
     9       this.element.addClass("ljq-tooltip-trigger")
    10         .on("mouseenter.ljq-tooltip", $.proxy(this._open, this))
    11         .on("mouseleave.ljq-tooltip", $.proxy(this._close, this));
    12     }, // end _create()
    13     destroy: function ()
    14     {
    15       this._tooltipDiv.remove();
    16       this.element.removeClass("ljq-tooltip-trigger")
    17         .off(".ljq-tooltip");
    18       $.Widget.prototype.destroy.apply(this, arguments);
    19     }, // end destroy()
    20     _open: function ()
    21     {
    22       var elementOffset = this.element.offset();
    23       this._tooltipDiv.css({
    24         position: "absolute",
    25         left: elementOffset.left,
    26         top: elementOffset.top + this.element.height()
    27       }).text(this.element.data("tooltip-text"));
    28       this._tooltipDiv.show();
    29     }, // end _open()
    30     _close: function ()
    31     {
    32       this._tooltipDiv.hide();
    33     } // end _close()
    34   }); // end widget.toolip()
    35 }(jQuery));
  7. 使用和禁用控件:控件内建了enable和disable方法,这样就可以设置this.options.disabled在true和false之间切换,我们只需要在方法之间检查这个值即可,例如在_open中检测
     1     _open: function ()
     2     {
     3       if (this.options.disabled)
     4       {
     5         return;
     6       } // end if
     7       var elementOffset = this.element.offset();
     8       this._tooltipDiv.css({
     9         position: "absolute",
    10         left: elementOffset.left,
    11         top: elementOffset.top + this.element.height()
    12       }).text(this.element.data("tooltip-text"));
    13       this._tooltipDiv.show();
    14     }, // end _open()

    调用.tooltip("disable"); tooltip("enable");可以达到控制this.options.disabled的目的

  8. 控件接受参数:为控件添加options属性并配置所需的默认参数,控件工厂会判断用户调用控件时传递的参数并覆盖默认参数:
     1 (function ($) {
     2   $.widget("ljq.tooltip", {
     3     options: {
     4       offsetX: 10,
     5       offsetY: 10,
     6       content: function () {
     7         return $(this).data("tooltip-text") + " default option";
     8       }
     9     },
    10     _create: function ()
    11     {
    12       this._tooltipDiv = $("<div></div>")
    13         .addClass("ljq-tooltip-text ui-widget "
    14           + "ui-state-highlight ui-corner-all")
    15         .hide().appendTo("body");
    16       this.element.addClass("ljq-tooltip-trigger")
    17         .on("mouseenter.ljq-tooltip", $.proxy(this._open, this))
    18         .on("mouseleave.ljq-tooltip", $.proxy(this._close, this));
    19     }, // end _create()
    20     destroy: function ()
    21     {
    22       this._tooltipDiv.remove();
    23       this.element.removeClass("ljq-tooltip-trigger")
    24         .off(".ljq-tooltip");
    25       $.Widget.prototype.destroy.apply(this, arguments);
    26     }, // end destroy()
    27     _open: function ()
    28     {
    29       if (this.options.disabled)
    30       {
    31         return;
    32       } // end if
    33       var elementOffset = this.element.offset();
    34       this._tooltipDiv.css({
    35         position: "absolute",
    36         left: elementOffset.left + this.options.offsetX,
    37         top: elementOffset.top + this.element.height() + this.options.offsetY
    38       }).text(this.options.content.call(this.element[0]));
    39       this._tooltipDiv.show();
    40     }, // end _open()
    41     _close: function ()
    42     {
    43       this._tooltipDiv.hide();
    44     } // end _close()
    45   }); // end widget.toolip()
    46 }(jQuery));

    调用控件时.tooltip({offsetX: 0, offsetY: 1});会自动覆盖默认参数

  9. 自定义子方法,系统提供了默认的如destroy子方法。我们可以提供自定义子方法供用户调用,控件工厂会保证我们的方法支持链式调用
    1     open: function ()
    2     {
    3       this._open();
    4     }, // end open()
    5     close: function ()
    6     {
    7       this._close();
    8     }, // end close()

    .tooltip("close");  tooltip("open");即可调用,自定义子方法可接受参数,通过控件调用子方法的字符串后传入参数如:

    close: function (msg)
    {
      console.log(msg);  
    }
    
    $("a").tooltip();
    $("a").tooltip("close", "this is argument");
  10. 触发控件事件:在控件函数中调用this._trigger("eventname");会在添加了该控件的元素上触发一个自定义事件,事件名带有控件名作为前缀如this._trigger("open");会在元素上触发tooltipopen,这样就可以在元素上添加监听器了
     1     _open: function ()
     2     {
     3       if (this.options.disabled)
     4       {
     5         return;
     6       } // end if
     7       var elementOffset = this.element.offset();
     8       this._tooltipDiv.css({
     9         position: "absolute",
    10         left: elementOffset.left + this.options.offsetX,
    11         top: elementOffset.top + this.element.height() + this.options.offsetY
    12       }).text(this.options.content.call(this.element[0]));
    13       this._tooltipDiv.show();
    14       this._trigger("open");
    15     }, // end _open()
    16     _close: function ()
    17     {
    18       this._tooltipDiv.hide();
    19       this._trigger("close");
    20     } // end _close()
  11. 了解了为jQuery和jQuery UI添加扩展的常见内容,可以总结如下:
    1. 通过使用立即调用函数表达式保证$在自定义模块内不会失效
    2. 无论扩展$全局函数或者jQuery对象方法,最多在$定义一个属性。多余的公共方法和属性应该添加到控件名字空间($.myPlugin.publicMethod或者$.fn.myPlugin.pluginProperty)
    3. 为控件提供一个默认选项设置:$.fn.myPlugin.defaults = { size: "large"};
    4. 允许控件用户覆盖默认设置:$.fn.myPlugin.defaults.size = "medium"; $("div").myPlugin({size: "small"})
    5. 扩展jQuery对象原型时,返回this提供链式调用: $("div").myPlugin().find("p").addClass("foo")
    6. 扩展jQuery原型时,内部需要调用this.each()确保内部调用
    7. 适当提供回调函数增加控件灵活性
    8. jQuery UI控件通过控件工厂定义并且执行操作时检查控件状态
    9. 为控件提供自动单元测试,如使用QUnit框架
    10. 使用版本控制工具,如Git,把代码放到GitHub允许其他人对代码贡献
    11. 给控件选择一个合适的license
    12. 给控件提供完善的文档
  12. 完整代码
      1 <!doctype html>
      2 <html lang="zh">
      3 <head>
      4     <meta charset="utf-8">
      5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
      6     <meta name="description" content="">
      7     <meta name="author" content="">
      8     
      9     <title>Template Index</title>
     10   <style>
     11   </style>
     12 
     13     
     14 </head>
     15 <body>
     16   <table id="inventory">
     17     <thead>
     18       <tr class="one">
     19         <th>Product</th>
     20         <th>Quantity</th>
     21         <th>Price</th>
     22       </tr>
     23     </thead>
     24     <tfoot>
     25       <tr class="two" id="sum">
     26         <td>Total</td>
     27         <td></td>
     28         <td></td>
     29       </tr>
     30       <tr id="average">
     31         <td>Average</td>
     32         <td></td>
     33         <td></td>
     34       </tr>
     35     </tfoot>
     36     <tbody>
     37       <tr>
     38         <td><a href="span.html" data-tooltip-text="Nutritious and delicious!">Spam</a></td>
     39         <td>4</td>
     40         <td>2.50</td>
     41       </tr>
     42       <tr>
     43         <td><a href="egg.html" data-tooltip-text="Fram fresh or scrambled!">Egg</a></td>
     44         <td>12</td>
     45         <td>4.32</td>
     46       </tr>
     47       <tr>
     48         <td><a href="gourmet-spam.html" data-tooltip-text="Chef Hermans's recipe">Gourmet Span</a></td>
     49         <td>14</td>
     50         <td>7.89</td>
     51       </tr>
     52     </tbody>
     53   </table>
     54 
     55     <script src="js/jquery.js"></script>
     56   <script src="js/jquery-ui-core.js"></script>
     57   <script>
     58   (function ($)
     59   {
     60     $.sum = function (array)
     61     {
     62       var total = 0;
     63       $.each(array,
     64         function (index, value)
     65         {
     66           value = $.trim(value);
     67           value = parseFloat(value) || 0;
     68           total += value;
     69         } // end function
     70       );
     71       return total;
     72     }; // end sum()
     73     
     74     $.average = function (array)
     75     {
     76       if ($.isArray(array))
     77       {
     78         return $.sum(array) / array.length;
     79       } // end if
     80       return "";
     81     }; // end average()
     82     
     83   }(jQuery));
     84   
     85 (function ($) {
     86   $.widget("ljq.tooltip", {
     87     options: {
     88       offsetX: 10,
     89       offsetY: 10,
     90       content: function () {
     91         return $(this).data("tooltip-text") + " default option";
     92       }
     93     },
     94     _create: function ()
     95     {
     96       this._tooltipDiv = $("<div></div>")
     97         .addClass("ljq-tooltip-text ui-widget "
     98           + "ui-state-highlight ui-corner-all")
     99         .hide().appendTo("body");
    100       this.element.addClass("ljq-tooltip-trigger")
    101         .on("mouseenter.ljq-tooltip", $.proxy(this._open, this))
    102         .on("mouseleave.ljq-tooltip", $.proxy(this._close, this));
    103     }, // end _create()
    104     destroy: function ()
    105     {
    106       this._tooltipDiv.remove();
    107       this.element.removeClass("ljq-tooltip-trigger")
    108         .off(".ljq-tooltip");
    109       $.Widget.prototype.destroy.apply(this, arguments);
    110     }, // end destroy()
    111     open: function ()
    112     {
    113       this._open();
    114     }, // end open()
    115     close: function ()
    116     {
    117       this._close();
    118     }, // end close()
    119     _open: function ()
    120     {
    121       if (this.options.disabled)
    122       {
    123         return;
    124       } // end if
    125       var elementOffset = this.element.offset();
    126       this._tooltipDiv.css({
    127         position: "absolute",
    128         left: elementOffset.left + this.options.offsetX,
    129         top: elementOffset.top + this.element.height() + this.options.offsetY
    130       }).text(this.options.content.call(this.element[0]));
    131       this._tooltipDiv.show();
    132       this._trigger("open");
    133     }, // end _open()
    134     _close: function ()
    135     {
    136       this._tooltipDiv.hide();
    137       this._trigger("close");
    138     } // end _close()
    139   }); // end widget.toolip()
    140 }(jQuery));
    141   </script>
    142   <script>
    143   $(function (){
    144     var inventory = $("#inventory tbody");
    145     var quantities = inventory.find("td:nth-child(2)")
    146       .map(function (index, qty){
    147         return $(qty).text();
    148       }).get();
    149     var sum = $.sum(quantities);
    150     $("#sum").find("td:nth-child(2)").text(sum);
    151     
    152     var prices = inventory.find("td:nth-child(3)")
    153       .map(function (index, qty){
    154         return $(qty).text();
    155       }).get();
    156     var average = $.average(prices);
    157     $("#average").find("td:nth-child(3)").text(average.toFixed(2));
    158   
    159   var data = [3, 4, 3, 4, 3, 4, 3, 4];
    160 console.log("sum: " + $.sum(data));
    161 console.log("avreage: " + $.average(data));
    162 $("a").tooltip();
    163   
    164   });
    165   </script>
    166 </body>
    167 </html>
原文地址:https://www.cnblogs.com/qiudeqing/p/3422101.html