一般来说,jQuery插件的开发分为两种:一种是挂在jQuery命名空间下的全局函数,也可称为静态方法;另一种是jQuery对象级别的方法,即挂在jQuery原型下的方法,这样通过选择器获取的jQuery对象实例也能共享该方法。

一、在讲解jQuery插件基本结构和模式前,先介绍下两个重要的方法:

1、$.extend(target, [object1], [objectN])

该方法主要用于合并两个或更多对象的内容(属性)到第一个对象,并返回合并后的第一对象。如果该方法只有一个参数target,则该参数将扩展jQuery的命名空间,即作为静态方法挂在jQuery全局对象下,如jQuery里的$.ajax、$.getJSON全局函数等:

  1. // 将hello方法挂在jQuery全局对象下,作为静态方法
  2. $.extend({
  3. hello: function() {alert("hello");}
  4. });

又如,在jQuery全局对象中扩展一个snsgou命名空间:

  1. $.extend({ snsgou: { } });

并将hello方法扩展到之前扩展的JQuery的snsgou命名空间中去:

  1. $.extend($.snsgou, {
  2. hello: function() {alert("hello");}
  3. });

在开发插件时,也可以将方法扩展到jQuery的原型中去,如:

  1. $.extend($.fn, {
  2. hello: function() {alert("hello");}
  3. });

值得注意的是:多个对象参数合并时,会破坏第一个对象的结构,所以可传递一个空对象作为第一个参数,如:$.extend({}, object1, object2);

另外,对于深度拷贝,即如果对象中也嵌套子对象,则会拷贝并覆盖子对象(如果有同名属性)全部的属性,需要设置第一个参数deep为true值,如:$.extend(true, target, object1, [objectN])。

2、$.fn.extend(target)

在jQuery中,$.fn本质上是等于jQuery的原型,即$.fn = $.prototype, 所以该方法实际上是为jQuery原型添加方法,即把target对象的方法添加到jQuery原型中去,这样jQuery对象实例就可以访问添加的方法了,这也是jQuery插件开发常用的方法,特别是添加多个接口时。如:

  1. // 将hello、hello2方法添加到jquery原型中
  2. $.fn.extend({
  3. hello: function() {alert("hello!");},
  4. hello2: function() {alert("hello again!);}
  5. });

如果添加单个方法到jQuery原型中,可使用$.fn.pluginName方法添加,如:

  1. // 将hello方法添加到jquery原型中
  2. $.fn.hello = function() {
  3. // ...
  4. };

二、在开发过一些 jQuery 插件后,慢慢的探索出了一套开发jQuery插件的基本结构和模式。这样在面对复杂多变的需要方案时,只要专注最主要的逻辑代码就行了。另外,使用相同的设计模式和架构也让修复bug或者二次开发更容易。

在这里分享一些平时遇到和总结的经验:

1、把全部代码放在闭包(一个即时执行函数)里

此时闭包相当于一个私有作用域,外部无法访问到内部的信息,并且不会存在全局变量的污染情况。官方创建开发规范的解释是:a) 避免全局依赖;b) 避免第三方破坏;c) 兼容jQuery操作符'$'和'jQuery '。如下所示:

  1. (function($) {
  2. // 局部作用域中使用$来引用jQuery
  3. // ...
  4. })(jQuery);

这段代码在被解析时可理解成以下代码:

  1. var jQ = function($) {
  2. // code goes here
  3. };
  4. jQ(jQuery);

2、提供插件的默认参数选项

一个扩展性良好的插件应该是可以让使用者根据需求自定义参数选项,并控制插件的行为,所以提供恢复默认选项是很有必要的。你可以通过jQuery的extend方法来设置这些选项:

  1. var defaults = {
  2. name: "snsgou",
  3. age: 22,
  4. job: "student",
  5. walk: function() {
  6. // ...
  7. }
  8. };

$.extend({}, defaults, options || {});

注:参数选项设置时也可以使用如下模式,即把参数对象挂在插件命名空间下:

  1. $.fn.pluginName.defaults = {
  2. name: "snsgou",
  3. age: 22,
  4. job: "student",
  5. walk: function() {
  6. // ...
  7. }
  8. };

3、遍历多个元素并返回

jQuery使用Sizzle选择器引擎,Sizzle可以为你的函数提供多元素操作(例如对所有类名相同的元素)。这是jQuery几个优秀的特性之一,在开发插件过程中即使你不准备为你的插件提供多元素支持,但为这做准备仍然是一个很好的实践。另外,jQuery有一个很好的特点就是可以进行方法级联,也可称为链式调用,所以我们不应该破坏这个特性,始终在方法中返回一个元素。如:

  1. function($) {
  2. // 参数选项设置...
  3. // 向jQuery原型中添加你的插件代码,用“pluginName”作为插件的函数名称。
  4. $.fn.pluginName = function(options) {
  5. // 遍历匹配的元素||元素集合,并返回this,以便进行链式调用。
  6. return this.each(function() {
  7. // 此处可通过this来获得每个单独的元素(jQuery对象)
  8. var _this = $(this);
  9.  
  10. });
  11. };
  12. })(jQuery);

4. 一次性代码放在主循环以外

这一条很重要,但是常常被忽略。简单的讲,如果你有一段代码是一堆默认值,只需要被实例化一次,而不是每次调用你插件功能的时候都需要实例化,你应该把这段代码放在插件方法的外面。这样可以让你的插件运行的更高效,节省内存。如:

  1. function($) {
  2. // 参数选项设置
  3. var defaults = {
  4. name: "snsgou",
  5. age: 22,
  6. job: "student",
  7. walk: function() {
  8. // ...
  9. }
  10. };
  11. // 向jQuery原型中添加你的插件代码,用“pluginName”作为插件的函数名称。
  12. $.fn.pluginName = function(options) {
  13. var opts = $.extend({}, defaults, options || {});
  14.  
  15. // 遍历匹配的元素||元素集合,并返回this,以便进行链式调用。
  16. return this.each(function() {
  17. // 此处可通过this来获得每个单独的元素(jQuery对象)
  18. var _this = $(this);
  19. // ...
  20. });
  21. };
  22. })(jQuery);

5、定义公有方法和私有方法

一般情况下,对于一个jQuery插件,一个基本的函数就可以很好地工作,但是对于复杂一点的插件就需要提供各种各样的方法和私有函数。你可能会使用不同的命名空间去为你的插件提供各种方法,但是添加过多的命名空间反而会使代码变得混乱,健壮性下降。所以最好的解决办法是适当地定义私有函数和方法。例子如下所示:

  1. (function($) {
  2. // 在我们插件容器内,定义一个私有方法
  3. var privateFunction = function() {
  4. // code here
  5. };
  6.  
  7. // 通过字面量创造一个对象,存储我们需要的公有方法
  8. var methods = {
  9. // 在字面量对象中定义每个单独的方法
  10. init: function() {
  11. // 为了更好的灵活性,对来自主函数,并进入每个方法中的选择器其中的每个单独的元素都执行代码
  12. return this.each(function() {
  13. // 为每个独立的元素创建一个jQuery对象
  14. var _this = $(this);
  15. // 执行代码 例如:privateFunction()
  16. });
  17. },
  18. destroy: function() {
  19. // 对选择器每个元素都执行方法
  20. return this.each(function() {
  21. // 执行代码
  22. });
  23. }
  24. };
  25.  
  26. $.fn.pluginName = function() {
  27. // 获取我们的方法,遗憾的是,如果我们用function(method){}来实现,这样会毁掉一切的
  28. var method = arguments[0];
  29.  
  30. // 检验方法是否存在
  31. if(methods[method]) {
  32. // 如果方法存在,存储起来以便使用
  33. // 注意:我这样做是为了等下更方便地使用each()
  34. method = methods[method];
  35.  
  36. // 如果方法不存在,检验对象是否为一个对象(JSON对象)或者method方法没有被传入
  37. } else if (typeof method === "object" || !method ) {
  38. // 如果我们传入的是一个对象参数,或者根本没有参数,init方法会被调用
  39. method = methods.init;
  40.  
  41. } else {
  42. // 如果方法不存在或者参数没传入,则报出错误。需要调用的方法没有被正确调用
  43. $.error("Method" + method + "does not exist on jQuery.pluginName");
  44. return this;
  45. }
  46.  
  47. // 调用我们选中的方法
  48. // 再一次注意我们是如何将each()从这里转移到每个单独的方法上的
  49. return method.call(this);
  50. };
  51.  
  52. })(jQuery);

注意我把 privateFunction 当做了一个函数内部的全局变量。考虑到所有的代码的运行都是在插件容器内进行的,所以这种做法是可以被接受的,因为它只在插件的作用域中可用。在插件中的主函数(pluginName)中,我检验了传入参数所指向的方法是否存在。如果方法不存在或者传入的是参数为对象, init 方法会被运行。最后,如果传入的参数不是一个对象而是一个不存在的方法,我们会报出一个错误信息。

下面是一些用法的例子

  1. // 为每个类名为 ".className" 的元素执行init方法
  2. $(".className").pluginName();
  3. $(".className").pluginName("init");
  4. $(".className").pluginName("init", {}); // 向init方法传入“{}”对象作为函数参数
  5. $(".className").pluginName({}); // 向init方法传入“{}”对象作为函数参数
  6.  
  7. // 为每个类名为 “.className” 的元素执行destroy方法
  8. $(".className").pluginName("destroy");
  9. $(".className").pluginName("destroy", {}); // 向destroy方法传入“{}”对象作为函数参数
  10.  
  11. // 所有代码都可以正常运行
  12. $(".className").pluginName("init", "argument1", "argument2"); // 把 "argument1" 和 "argument2" 传入 "init"
  13.  
  14. // 不正确的使用
  15. $(".className").pluginName("nonexistantMethod");
  16. $(".className").pluginName("nonexistantMethod", {});
  17. $(".className").pluginName("argument1"); // 会尝试调用 "argument1" 方法
  18. $(".className").pluginName("argument1", "argument2"); // 会尝试调用 "argument1" ,“argument2”方法
  19. $(".className").pluginName("privateFunction"); // "privateFunction" 不是一个方法

6、添加持久性数据

在插件开发过程中,有时需要在插件中保存设置和信息,这时jQuery中的$.data函数就可以派上用场了。使用时,它会尝试获取和元素相关的数据,如果数据不存在,它就会创造相应的数据并添加到元素上。一旦你使用了$.data来为元素添加信息,请确认你已经记住remember,当不再需要数据的时候,用$.removeData函数来删除相应的数据。

  1. (function($) {
  2. var privateFunction = function() {
  3. // 执行代码
  4. }
  5.  
  6. var methods = {
  7. init: function(options) {
  8.  
  9. // 在每个元素上执行方法
  10. return this.each(function() {
  11. var _this = $(this);
  12.  
  13. // 尝试去获取settings,如果不存在,则返回“undefined”
  14. var settings = _this.data("pluginName");
  15.  
  16. // 如果获取settings失败,则根据options和default创建它
  17. if (typeof settings === "undefined") {
  18.  
  19. var defaults = {
  20. propertyName: "value",
  21. onSomeEvent: function() {}
  22. };
  23.  
  24. settings = $.extend({}, defaults, options);
  25.  
  26. // 保存我们新创建的settings
  27. _this.data("pluginName", settings);
  28. } else {
  29. / 如果我们获取了settings,则将它和options进行合并(这不是必须的,你可以选择不这样做)
  30. settings = $.extend({}, settings, options);
  31.  
  32. // 如果你想每次都保存options,可以添加下面代码:
  33. // _this.data("pluginName", settings);
  34. }
  35.  
  36. // 执行代码
  37.  
  38. });
  39. },
  40. destroy: function(options) {
  41. // 在每个元素中执行代码
  42. return $(this).each(function() {
  43. var _this = $(this);
  44.  
  45. // 执行代码
  46.  
  47. // 删除元素对应的数据
  48. _this.removeData("pluginName");
  49. });
  50. },
  51. val: function(options) {
  52. // 这里的代码通过.eq(0)来获取选择器中的第一个元素的,我们或获取它的HTML内容作为我们的返回值
  53. var someValue = this.eq(0).html();
  54.  
  55. // 返回值
  56. return someValue;
  57. }
  58. };
  59.  
  60. $.fn.pluginName = function() {
  61. var method = arguments[0];
  62.  
  63. if (methods[method]) {
  64. method = methods[method];
  65. arguments = Array.prototype.slice.call(arguments, 1);
  66. } else if (typeof method === "object" || !method ) {
  67. method = methods.init;
  68. } else {
  69. $.error("Method" + method + "does not exist on jQuery.pluginName");
  70. return this;
  71. }
  72.  
  73. return method.apply(this, arguments);
  74.  
  75. }
  76.  
  77. })(jQuery);

在上面的代码中,首先检验元素的数据是否存在。如果数据不存在,“options”和“default”会被合并,构建成一个新的settings,然后用$.data()保存在元素中。

参考:http://www.cnblogs.com/%86%e5%bc%80%e5%8f%91.html

jQuery插件开发 总结的更多相关文章

  1. JavaScript学习笔记(四)——jQuery插件开发与发布

    jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...

  2. JavaScript学习总结(四)——jQuery插件开发与发布

    jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...

  3. jQuery插件开发精品教程,让你的jQuery提升一个台阶

    要说jQuery 最成功的地方,我认为是它的可扩展性吸引了众多开发者为其开发插件,从而建立起了一个生态系统.这好比大公司们争相做平台一样,得平台者得天下.苹果,微软,谷歌等巨头,都有各自的平台及生态圈 ...

  4. jquery插件开发

    jQuery是一个封装的很好的类,比如我们用语句$("#btn1") 会生成一个 jQuery类的实例. 一.jQuery插件开发注意要点 1.使用闭包,避免全局依赖,避免第三方破 ...

  5. jQuery插件开发(溢出滚动)

    声明:此程序仅针对手机端,简单的封装一个插件,意在记载插件的开发过程,如有错误及不足之处,还望即时指出. 移动开发的时候,我们经常会遇到滑动事件,众所周知手机端滑动主要依靠touch事件.最近接连遇到 ...

  6. 从零开始学jQuery插件开发

    http://www.w3cfuns.com/notes/19462/ec18ab496b4c992c437977575b12736c.html jQuery 最成功的地方,是它的可扩展性,通过吸引了 ...

  7. jquery插件开发继承了jQuery高级编程思路

    要说jQuery 最成功的地方,我认为是它的可扩展性吸引了众多开发者为其开发插件,从而建立起了一个生态系统.这好比大公司们争相做平台一样,得平台者得天下.苹果,微软,谷歌等巨头,都有各自的平台及生态圈 ...

  8. jQuery插件开发(转)

    jQuery插件开发全解析 jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命 ...

  9. jQuery插件开发的两种方法及$.fn.extend的详解

    jQuery插件开发分为两种: 1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.ex ...

  10. Jquery插件开发学习

    一:导言 有些WEB开发者,会引用一个JQuery类库,然后在网页上写一写$("#"),$("."),写了几年就对别人说非常熟悉JQuery.我曾经也是这样的人 ...

随机推荐

  1. Hadoop平台K-Means聚类算法分布式实现+MapReduce通俗讲解

        Hadoop平台K-Means聚类算法分布式实现+MapReduce通俗讲解 在Hadoop分布式环境下实现K-Means聚类算法的伪代码如下: 输入:参数0--存储样本数据的文本文件inpu ...

  2. Windows7下打开特定的端口

    往往我们发布到IIS的网站多了,80的端口不能满足的情况下,我们就会想到设定其它端口来使用.当然还可以通过改变host文件来实现,这里就不细说了.回到端口,在windows7系统下怎么实现呢?下面将带 ...

  3. crond守护进程

    Linux系统任务计划/etc/crontab cron的主配置文件,可以定义PATHcron格式如下:# .----------------分钟 (0 - 59)# | .------------- ...

  4. PHP异常处理类(文件上传提示)

    知识点: 大部分时候我们的代码总有各种各样的bug,新手程序员(比如我)最经常的工作就是不停的报错和echo变量,一个好的异常处理类可以帮我们更快+更容易理解报错代码的问题,同时,异常处理还可以避免一 ...

  5. hdu 2553 N皇后问题 (DFS)

    N皇后问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  6. GYM - 101147 J.Whistle's New Car

    题意: 给出一颗有点权和边权的树.求每一个点u的子树中有多少点v,使得点v到点u的距离小于等于点v的权值. 题解: 对于每一个点,倍增的预处理出他的祖宗节点及距离.根据预处理的结果求出每个点能到的最远 ...

  7. ZOJ 1081 Points Within | 判断点在多边形内

    题目: 给个n个点的多边形,n个点按顺序给出,给个点m,判断m在不在多边形内部 题解: 网上有两种方法,这里写一种:射线法 大体的思想是:以这个点为端点,做一条平行与x轴的射线(代码中射线指向x轴正方 ...

  8. 雅礼集训 Day3 T2 u 解题报告

    u 题目背景 \(\frac 14\) 遇到了一道水题,完全不会做,于是去请教小\(\text{D}\).小\(\text{D}\)看了一眼就切掉了这题,嘲讽了\(\frac 14\)一番就离开了. ...

  9. 《R语言实战》读书笔记--学习张丹日志

    从张丹的日志(http://blog.fens.me/rhadoop-r-basic/)中第九条对象看到R对象的几个总结: 1.内在属性 mode length 所有对象都有的属性 2.外部属性 at ...

  10. 《c程序设计语言》读书笔记-5.5-指针实现strncpy,strncat,strncmp

    #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string.h> ...