首页 > 代码库 > 第七章(插件的使用和写法)(7.6 编写 jQuery 插件)

第七章(插件的使用和写法)(7.6 编写 jQuery 插件)

7.6.1 插件的种类

编写插件的目的是给已经有的一系列方法或函数做一个封装,以便在其他地方重复使用,方便后期维护和提高开发效率。

jQuery 的插件主要分为3种类型。

1 封装对象方法的插件

这种插件是将对象方法封装起来,用于对通过选择器获取的 jQuery 对象进行操作,是最常见的一种插件。

据不完全统计,95%以上的 jQuery 插件都是封装对象方法的插件,此类插件可以发挥出 jQuery 选择器的强大优势。有相当一部分的 jQuery 的方法,都是在 jQuery 脚本库内部通过这种形式,“插”在内核上,例如 parent() 方法,appendTo() 方法和 addClass() 方法等不少DOM操作方法。

不少用户对 jQuer 没有提供 color() 方法而表示遗憾,不得不使用 css("color")来代替,下面会编写一个 color() 方法的 jQuery 插件。

2 封装全局函数的插件

可以将独立的函数加到 jQuery 命名空间之下,例如第一章提到解决冲突用的 jQuery.noConflict() 方法、常用的 jQuery.ajax() 方法以及去除首位空格的 jQuery.trim() 方法等,都是 jQuery 内部作为全局函数的插件附加到内核上去的。

3 选择器插件

个别情况下,会需要用到选择器插件,虽然 jQuery 的选择器十分强大,但还是会需要扩充一些自己喜欢的选择器,例如用: color(red) 来选择所有红色字的元素之类的想法。

7.6.2 插件的基本要点

? jQuery 插件的文件名推荐命名为 jquery.[插件名].js,以免和其他 .js 库插件混淆,例如: jquery.color.js

? 所有的对象方法都应当附加到 jQuery.fn 对象上,而所有的全局函数都应当附加到 jQuery 对象本身上

? 在插件内部,this 指向的是当前通过选择器获取的 jQuery 对象,而不是一般的方法那样,例如 click() 方法,内部的this 指向的是 DOM 元素

? 可以通过 this.each 来遍历所有元素

? 所有的方法或函数插件,都应当以分号结尾,否则压缩的时候可能出现问题。为了更稳妥些,甚至可以在插件头部先加上一个分号,以免他人的不规范代码给插件带来影响

? 插件应该返回一个 jQuery 对象,以保证插件的可链式操作,除非插件需要返回的是一些需要获取的量,例如字符串或者数组等

? 避免在插件内部使用 $ 作为 jQuery 对象的别名,而应使用完整的 jQuery 来表示,这样可以避免冲突。当然,也可以利用闭包技巧来回避这个问题,使插件内部继续使用 $ 作为 jQuery 的别名。

7.6.3 插件中的闭包

闭包:允许使用内部函数(即函数定义和函数表达式位于另一个函数的函数体内),而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数,当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包

闭包含义:即内部函数会在外部函数返回后被执行,而当这个内部函数执行时,它仍然必须访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响。

利用闭包特性,既可以避免内部临时变量影响全局空间,又可以在插件内部继续使用 $ 作为 jQuery 的别名,常见的 jQuery 插件都是以下形式:

(function(){
   /*这里置放代码*/
})();

首先定义一个匿名函数 function(){  /*置放代码*/  },然后用括号括起来,变成( function(){  /*置放代码*/  }) 这种形式,最后通过 () 这个运算符来执行,可以传递参数进去,以供内部函数使用。

// 注意为了更好的兼容性,开始前有个分号
; (function($){                     //此处将 $ 作为匿名函数的形参
         /*这里置放代码,可以使用 $ 作为 jQuery 的缩写别名*/
})(jQuery);                       // 这里就将 jQuery 作为实参传递给匿名函数了

上述代码是一种常见的 jQuery 插件结构。

代码 :  

    ; (function($){
        // 这里编写插件的代码,可以继续是哦那个 $ 作为 jQuery 的别名
        // 定义一个局部变量 foo, 仅函数内部可以访问,外部无法访问

        var foo;
        var bar = function(){
            /*
                在匿名函数内部的函数都可以访问foo,即便是匿名函数的外部调用 bar()的时候,也可以在 bar() 的内部访问到 foo,但在匿名函数的外部直接访问 foo是做不到的
            */
        }

        /*
                下面的语句让匿名函数内部的函数 bar() 逃逸到全局可访问的范围内,这样就可以在匿名函数的外部通过调用 jQuery.BAR() 来访问内部定义的函数 bar(),并且内部函数 bar() 也能访问匿名函数内的变量 foo
        */
        $.BAR = bar;
    })(jQuery);

7.6.4 jQuery 插件的机制 

jQuery 提供了两个用于扩展 jQuery 功能的方法,即 jQuery.fn.extend() 方法和 jQuery.extend() 方法,前者用于扩展之前提到的3种类型插件中的第一种,后者用于扩展后两种插件。这两个方法都接受一个参数,类型为 Object,Object 对象的“名/值对”分别代表“函数或方法名/函数主体”

jQuery.extend() 方法除了可以用于扩展 jQuery 对象外,还有一个很强大的功能,就是用于扩展已有的 Object 对象。

jQuery 代码如下: 

jQuery.extend(target,obj1,..........[objN]);

用一个或多个其他对象来扩展一个对象,然后返回被扩展的对象。

例如合并 settings 对象和 options 对象,修改并返回 settings 对象

var settings = {validate: false, limit:5, name:"foo"};
var options  = {validate:true, name:"bar"};
var newOptions = jQuery.extend(settings, options);

// 结果为:
newOptions = {validate:true , limit: 5, name:"bar"};

jQuery.extend() 方法经常被用于设置插件方法的一系列默认参数,如下所示:

function foo(options){
    options = jQuery.extend({
        name: "bar",
        length: 5,
        dataType: "xml"   /*默认参数*/    
    }, options );         /*options 为传递的参数*/
};

如果用户调用 fooff() 方法的时候,在传递的参数 options 对象中设置了相应的值,那么就使用设置的值,否则使用默认值。代码如下:

foo({ name:"a",length:"4",dataType:"json" });
foo({ name:"a",length:"4" });
foo({ name:"a" });
foo();

通过使用 jQuery.extend() 方法,可以很方便的用传入的参数来覆盖默认值,此时,对方法的调用依旧保持一致,只不过要传入的是一个映射而不是一个参数列表。

特点: 这种机制比传统的每个参数都去检测的方式不仅灵活而且更简洁,此外,使用命名参数意味着再添加新选项也不会影响过去编写的代码,使代码更加直观明了。

7.6.5 编写 jQuery 插件

1 封装 jQuery 对象方法的插件

? 编写设置和获取颜色的插件

首先编写一个 color() 插件,该插件用于实现以下两个功能:

① 设置匹配元素的颜色

② 获取匹配的元素(元素集合中的第 1 个)的颜色

首先将该插件按规范命名为 jquery.color.js

然后在 Javascript 文件里搭好框架,如下:

; (function($){
     // 这里写插件代码
})(jQuery);

由于是对 jQuery 对象的方法扩展,因此采用扩展第 1 类插件的方法 jQuery.fn.extend() 来编写

; (function($){
   $.fn.extend({
       "color":function(value){
          // 这里写插件代码
        }
    });
})(jQuery);

这里给这个方法提供一个参数 value ,如果调用方法的时候传递了 valud 这个参数,那么就是用这个值来设置字体颜色,否则就是获取匹配元素的字体颜色的值。

首先实现第一个功能,设置字体颜色。

只需要简单地调用 jQuery 提供的 css() 方法,直接写成 this.css("color", value ) 即可。

注意:插件内部的 this 指向的是 jQuery 对象,而非普通的 DOM 对象,接下来要注意,插件如果不需要返回字符串之类的特定值,应当使其具有可链接性。为此,直接,直接返回这个 this 对象,由于 .css() 方法也会返回调用它的对象,即此处的 this  , 因此可以将代码写成:

; (function($){
   $.fn.extend({
       "color":function(value){
           return this.css("color",value);
        }
   });
})(jQuery);    

接下来实现第二个功能,如果没有给方法传递参数,那么就是获取集合对象中第1个对象的 color 的值,由于 css() 方法本身就具有返回第 1 个匹配元素的样式值的功能,因此此处无需通过 eq() 来获取第1 个元素,只要将这两个功能结合起来,判断一下 value 是否是 undefined 即可。

jQuery 代码如下:

; (function($){
    $.fn.extend({
        "color":function(value){
            if(value =http://www.mamicode.com/= undefined){
                return this.css("color");
            }else{
                return this.css("color", value);
            }
        }
    });
})(jQuery);

此时,color() 插件的功能已经全部实现了。通过该插件可以获取和设置元素的 color 值。

实际上,css() 方法内部已经有判断 value 是否为 undefined 的机制,所以才可以根据传递参数的不同而返回不同的值。因此,可以借助 css() 方法的这个特性来处理该问题。 删除 if() 部分,最终剩余的代码实际上与先前那一段是一样的,jQuery 代码如下:

; (function($){
    $.fn.extend({
        "color":function(value){
                return this.css("color");
        }
    });
})(jQuery);

示例测试:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        .a{color: red;}
    </style>
    <script type="text/javascript" src="jquery.js"></script>
</head>
<body>
<body>
<div class="a">red</div>
<div style="color:blue">blue</div>
<div style="color:green">green</div>
<div style="color:yellow">yellow</div>

<script type="text/javascript">
 // 插件编写
 ;(function($){
     $.fn.extend({
         "color":function(value){
             if(value == undefined){
                 return this.css("color");
             }else{
                 return this.css("color",value);
             }
         }
     });
 })(jQuery);
 // 插件应用
 $(function(){
     // 查看第一个 div 的color 样式值
     alert($("div").color()+"\n 返回字符串,证明此插件可用。");

     // 把所有的 div 字体颜色设为红色
     alert($("div").color("red")+"\n 返回object 证明得到的是 jQuery对象")
 })
</script>
</body>
</html>

 

技术分享

 获取第一个元素的color值

 技术分享

设置元素的 color  属性为红色

如果需要定义一组插件,可以使用如下写法:

 ;(function($){
     "color":function(value){
         // 插件代码
     },
     "border":function(value){
         // 插件代码
     },
     "background":function(value){
         // 插件代码
     }
 })(jQuery);

 扩 展  

随机更换字体颜色

 // 插件编写
 ;(function($){
     $.fn.extend({
         "color":function(value){
             if(value =http://www.mamicode.com/= undefined){
                 return this.css("color");
             }else{
                 return this.css("color",value);
             }
         }
     });
 })(jQuery);
 // 插件应用
 $(function(){
     $("div").click(function(){
         var color = $(this).text();
         $("div").color(color);
     })
 })

技术分享技术分享技术分享

点击文字,随机更换颜色

? 表格隔行变色插件

jQuery 代码如下:

<script>
  $(function(){
        $("tbody>tr:odd").addClass("odd");
        $("tbody>tr:even").addClass("even");
        $(‘tbody>tr‘).click(function() {
            //判断当前是否选中
            var hasSelected=$(this).hasClass(‘selected‘);
            //如果选中,则移出selected类,否则就加上selected类
            $(this)[hasSelected?"removeClass":"addClass"](‘selected‘)
                //查找内部的checkbox,设置对应的属性。
                .find(‘:checkbox‘).attr(‘checked‘,!hasSelected);
        });
        // 如果单选框默认情况下是选择的,则高色.
        $(‘tbody>tr:has(:checked)‘).addClass(‘selected‘);
  })
</script>

首先把插件取名为:alterBgColor,然后为该插件方法搭好框架,jQuery 代码如下:

 // 插件编写
 ;(function($){
     $.fn.extend({
         "alterBgColor":function(options){
             // 插件代码
         }
     });
 })(jQuery);

框架完成后,接下来需要为 options 定义默认值,默认构成这样 ({odd:“odd”,even:"even",selected:"selected"}) 一个Object 。这样就可以通过 $("#sometable").alterBgColor({odd:“odd”,even:"even",selected:"selected"}) 自定义奇偶行的样式类名以及选中后的样式类名。同时,直接使用 $("#sometable").alterBgColor() 就可以应用默认的样式类名。

jQuery 代码如下:

; (function($){
    $.fn.extend({
        "alterBgColor":function(options){
            options = $.extend({
                odd:"odd",  /*偶数行样式*/
                even:"even", /*奇数行样式*/
                selected:"selected"  /*选中行样式*/
            },options);
        }
    });
})(jQuery);

如果在后面的程序中需要使用 options 对象中的属性,可以使用如下方式来获得:

options.odd;   //获取options 对象中的 odd属性的值
options.even;  //获取options 对象中的 even属性的值
options.selected  //获取options 对象中的 selected属性的值

接下来就需要把这些值放到程序中,来代替先前程序中的固定值。

最后就是匹配元素的问题了,显然不能直接用 $("tbody>tr")选择表格行,这样会使页面中全部的 <tr>元素都隔行变色,应该使用选择器选中某个表格,然后执行 alterBgColor() 方法后,将对应的表格内<tr>元素进行隔行变色。因此,需要把所有通过 $("tbody>tr")选择的对象改写成 $("tbody>tr", this),表示在匹配的元素内(当前表格内)查找,并应用上一步中的默认值。

jQuery 代码如下:

    ;(function($) {
        $.fn.extend({
            "alterBgColor":function(options){
                //设置默认值
                options=$.extend({
                    odd:"odd",    /* 偶数行样式*/
                    even:"even", /* 奇数行样式*/
                    selected:"selected" /* 选中行样式*/ 
                },options);
                $("tbody>tr:odd",this).addClass(options.odd);
                $("tbody>tr:even",this).addClass(options.even);
                $(‘tbody>tr‘,this).click(function() {
                    //判断当前是否选中
                    var hasSelected=$(this).hasClass(options.selected);
                    //如果选中,则移出selected类,否则就加上selected类
                    $(this)[hasSelected?"removeClass":"addClass"](options.selected)
                        //查找内部的checkbox,设置对应的属性。
                        .find(‘:checkbox‘).attr(‘checked‘,!hasSelected);
                });
                // 如果单选框默认情况下是选择的,则高色.
                $(‘tbody>tr:has(:checked)‘,this).addClass(options.selected);
                return this;  //返回this,使方法可链。
            }
        });
    })(jQuery);

在代码最后,返回this ,让这个插件具有可链性。

测试插件

构建2个表格

<title></title>
    <style type="text/css">
    table        { border:0;border-collapse:collapse;}
    td    { font:normal 12px/17px Arial;padding:2px;width:100px;}
    th            { font:bold 12px/17px Arial;text-align:left;padding:4px;border-bottom:1px    solid #333;}
    .even        { background:#FFF38F;}  /* 偶数行样式*/
    .odd        { background:#FFFFEE;}  /* 奇数行样式*/
    .selected    { background:#FF6500;color:#fff;}
    </style>
</head>
<body>
<table id="table1">
    <thead><tr><th> </th><th>姓名</th><th>性别</th><th>暂住地</th></tr></thead>
    <tbody>
        <tr>
            <td><input type="checkbox" name="choice" value=""/></td>
            <td>张山</td>
            <td></td>
            <td>浙江宁波</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="choice" value="" /></td>
                <td>李四</td>
            <td></td>
            <td>浙江杭州</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="choice" value="" checked="checked" /></td>
                    <td>王五</td>
            <td></td>
            <td>湖南长沙</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="choice" value="" /></td>
            <td>找六</td>
            <td></td>
            <td>浙江温州</td>    
        </tr>
        <tr>
        <td><input type="checkbox" name="choice" value="" /></td>
                <td>Rain</td>
            <td></td>
            <td>浙江杭州</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="choice" value="" checked="checked" /></td>
            <td>MAXMAN</td>
            <td></td>
            <td>浙江杭州</td>
        </tr>
    </tbody>
</table>


<br /><br />


<table id="table2">
    <thead><tr><th> </th><th>姓名</th><th>性别</th><th>暂住地</th></tr></thead>
    <tbody>
        <tr>
            <td><input type="checkbox" name="choice" value=""/></td>
            <td>张山</td>
            <td></td>
            <td>浙江宁波</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="choice" value="" /></td>
                <td>李四</td>
            <td></td>
            <td>浙江杭州</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="choice" value="" checked="checked" /></td>
                    <td>王五</td>
            <td></td>
            <td>湖南长沙</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="choice" value="" /></td>
            <td>找六</td>
            <td></td>
            <td>浙江温州</td>    
        </tr>
        <tr>
        <td><input type="checkbox" name="choice" value="" /></td>
                <td>Rain</td>
            <td></td>
            <td>浙江杭州</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="choice" value="" checked="checked" /></td>
            <td>MAXMAN</td>
            <td></td>
            <td>浙江杭州</td>
        </tr>
    </tbody>
</table>
</body>

技术分享

应用插件

// 插件应用
$(function(){
    $("#table2")
        .alterBgColor()   //应用插件
        .find("th").css("color","red");   // 可链式操作
})

 技术分享

注意:

jQuery 的选择符可能会匹配1个或多个元素,因此,在编写插件时必须考虑到这些情况,可以在插件内部调用 each() 方法来遍历匹配元素,然后执行相应的方法,this 会依次引用每个 DOM 元素

;(function($){
    $.fn.extend({
        "somePlugin":function(options){
            return this.each(function(){
                // 这里置放插件代码
            });
        }
    });
})(jQuery);

2 封装全局函数的插件

 

第七章(插件的使用和写法)(7.6 编写 jQuery 插件)