JQuery插件机制

js语言灵活性很强,很多的语法是其它语言所不及的,非常的方便。

在JS中{}是对象包,[]是数组包,所以很多地址可以看到{test:1,tes2:2}等内容这个实际就是一个对象包含了两个属性。[1,2,3,4]这个实际就是一个数组有四个元素。

090041529.jpg090148102.jpg

开发JQuery插件实际就是给JQuery对象或选择器对象添加函数,当然可以使用的方法有很多种,如果我们只给JQuery添加一个函数其实可以用最简单的方法

jQuery.method_name=function(){

   函数主体

}

可以通过jQuery.method_name();来调用这个方法

当然往往在实际中很少出现只添加一个函数,一般会添加多个函数和多个属性给JQuery或选择器对象。那么用上面的方法就不那么方便。这个时候就可以使用JQuery内部提供的一个插件机制来批量添加,这样不但方便,而且可以把一个功能块包装在一个插件体内,方便以后修改与更新。

以下是JQuery插件函数代码(jQuery v@1.8.0),这段代码在JQuery的共用性很高如果不了解框架整体不要去修改。

取出JQuery插件机制代码分析下,进一步了解JQuery插件运行情况,从而更好的去开发插件。当然如有不当之处还请留言指正。

/* JS中可以不写入传参,函数内部可以通过arguments来获取传入的参数集合通过下标可以取出对应的参数(这算的上是JS的特殊功能吧),函数也运用了条件性递归处理。*/

p.extend = p.fn.extend = function() {

       /* 初始化局部基本变量,其中 h 取出第一个传入的参数(如果没有传入参数则是undefined),j 获取传入参数的个数 */

       var a, c, d, e, f, g, h = arguments[0] || {}, i = 1, j = arguments.length, k = !1;

       /* 以下代码是判断第一个参数不能为布尔值,如果是保存这个布尔值到k中,再取出第二个参数到h中如果没有第二个参数写入空对象。 */

       typeof h == "boolean" && (k = h, h = arguments[1] || {}, i = 2),

       /* 以下代码是判断 h(传入的第一个参数或第二个参数)是否为对象,不是对象再判断是否为函数,如果也不是函数就写入空对象 */

       typeof h != "object" && !p.isFunction(h) && (h = {}),

       /*以下代码判断传入的参数个数是否与 i(如果第一个参数不是布尔值则为1否则为2)相等,如果相等则h为对象本身(JQuery或选择器对象)然后i减1 */

       j === i && (h = this, --i);

       /* 通过上面的初始操作后:

          没有传入参数: i  为 1,h 为 空对象 ,k 为 false 无意义调用

          传入一个参数:参数为布尔值时 i 为 2,h 为 空对象,k 为 传入的布尔值 无意义调用;否则 i 为 0 ,h 为 JQuery对象或选择器对象 , k 为false 插件常用方式传入的(参数是对象一般以{}形式传入)

          传入两个参数:第一个参数为布尔值 i 为 1 ,h 为 JQuery对象或选择器对象,k 为 传入的布尔值;否则 i 为 1 ,h 为 传入的第一个参数(对象或函数)或空对象,k 为 false

          传入两个以上参数:第一个参数为布尔值 i 为 2 ,h为 传入的第二个参数(对象或函数)或空对象,k 为 传入的布尔值;否则 i 为 1 ,h 为传入的第一个参数(对象或函数)或空对象, k 为false

       通过for循环出传入的参数(如果i不大于j那循环不成立)这个循环体主要是添加扩展,如果没有进入循环体内的调用都是无意义的调用

       循环体内要取到的的变量包含 h , k 。这两个变量直接受传入的参数影响。如果第一个参数是布尔值那么h就是第二个参数

        */

       for (; i < j; i++)

           /* 判断是否有传入对应个数的参数 */

           if ((a = arguments[i]) != null)

               /* 循环出参数的内容 */

               for (c in a) {

                   /* 取出 h (对象)中对应下标的元素,当然如果没有那么 d 为undefined */

                   d = h[c],

                    /* 取出循环 a 中对应下标的元素 */

                    e = a[c];

                   /* 判断两个取出的内容是否绝对性的相同,如果是跳出本次循环处理,进入下次循环处理中 */

                   if (h === e)

                        /* 进行下一次循环 */

                       continue;

                   /* 如果 k ,e 为真并且 e 是数组或单纯对象(非DOM对象)时成立 */

                   k && e && (p.isPlainObject(e) || (f = p.isArray(e))) ?

                       /* 以上条件成立时执行:如果e是数组时f为真 */

                       (f ?

                           /*如果e是数组那么置f为false,当d为真并且是数组时g保存d,否则g为空数组对象。*/

                           (f = !1, g = d && p.isArray(d) ? d :[]) :

                           /*如果e不是数组。当d是单纯对象(非DOM对象)时g保存d,否则g为空对象。*/

                           g = d && p.isPlainObject(d) ? d : {},

                           /* h在指定的下标进行递归处理再扩展功能(但这里扩展的是h指定下标元素功能。),这次递归中k必为真,g为空对象或空数组或为d,e为传入的第二个及以后的参数(每次只是一个参数内的属性或方法)*/

                       h[c] = p.extend(k, g, e)) :

                       /* 以上条件不成立时执行:b是框架创建时传入的第二个参数,一般的框架只传入了window所以 b 在这里只是undefined,如果你有高级的应用传入第二个参数来指定b。所以在这里只分析e不等于undefined时 把e写入到h指定下标c中(循环a出来的下标,这里可以看到给h添加了函数或属性,如果h是框架对象那么添加插件功能就实现了) */

                        e !== b && (h[c] = e)

               }

       /* 返回主要是针对递归操作 */

       return h

}

根据上面的代码可以看出扩展JQuery功能:

   jQuery.extend(Object)或$.extend(Object) 给框架扩展功能

   jQuery.fn.extend(Object)或$.fn.extend(Object) 给选择器扩展功能

Object一般可以直接以{}形式传入例如:{test:function(){alert('test')},test1:null}

也可以用其它方法,一般参数是对象或数组。

   可以总结一下:扩展功能只要传入对象或数组一个参数就可以,当然多个也是可以的。如果先扩展过某个属性(属性为单纯对象或数组),后还想给这个对象或数组添加一些功能或元素时,就可以在传入两个参数(禁止传入三个参数,否则就是扩展第二个参数的功能而非框架的功能),第一个为布尔值true第二个为要添加的对象或数组,内部下标不要重复,否则会被覆盖。

在插件函数内我们可以使用待扩展的框架所有方法与属性,可以通过this来调用。

例:添加一个插件,要求能取出指定元素下的所有的图片元素并在浏览器没有移动到前不显示图片,移动到后才显示。

   代码如下:

$.fn.extend

({
   imgMoverStart:function(imgLoad){ //入囗处,参数为IMG标签里保存图片路径的属性标签
       this.each(function(){ //循环出元素
           if(this.nodeName.toLowerCase()=='img')//判断循环出来的元素是不是图片
               $(this).imgShow(imgLoad);//是图片加载显示处理
           else //不是再循环子元素
               $(this).find('img').each(function(){//取出子元素中的图片元素
                   $(this).imgShow(imgLoad);//加载显示处理
               });
       });
   },
   imgShow:function(imgLoad){//图片显示处理
       if(this.get(0).nodeName.toLowerCase()!='img')return;//判断如果调的元素不是图片标签取消操作
       var base=this;//保存对象本身
       $(window).resize(function(){//添加窗囗大小变动事件
           $(this).judge(base,imgLoad);//判断处理显示
       }).scroll(function(){//添加滚动事件
           $(this).judge(base,imgLoad);//判断处理显示
       }).judge(base,imgLoad);//初始第一次要必须显示的图片
   },
   judge:function(img,imgLoad){//判断显示图片
       var base=this;//保存对象本身
       setTimeout(function(){//延时处理,减少大量同时请求
           var offset=img.offset(),imgimg.attr(imgLoad); //取出图片的TOP与图片地址数据
           base.scrollTop()+base.height()>offset.top&&img.attr('src')!==imgSrc&&img.attr('src',imgSrc);//判断当前窗囗是否到图片的位置,是加载图片
       },100)//延时0.1秒
   }
});
$(window).ready(function(){$('img').imgMoverStart('load_src');})//启动插件

上面这段代码主要是处理上下滚动时当窗显示的内容到了图片的上端位置时开始加载图片。这个功能很像JQuery的lazyload插件,当然没有这个插件功能全。

插件是扩展选择器对象,一共扩展了三个方法,那么只要通过 $.('筛选字符').扩展方法名 就可以使用这个插件。在插件内的this就是这个选择器对象,所以我们可以直接使用this.each() this.get() 等选择器可以使用的方法基本上都可以拿来用。非常的方便。当然还有很多的扩展方法。但基本相思就是给框架添加功能。