如何写jQuery插件和拓展

2015-12-08 散崖 1595人已阅读

这是早之前在cnblog写的一篇文章,现在就把它搬到自己博客上,正所谓我们只是大自然的搬运工…laugh

说起jQuery插件,很多人的脑海种已经有了一定的雏形,仿佛感觉仅仅就是那样子,事实呢?当你看了Bootstrap.js,品读了slidesjs,观摩了jquery.cycle2.js,不禁发现,原来插件的世界千变万化,细微之处总是不容易让人发觉,世界那么大,那么我们就一起去看看它到底长什么样子?

工欲善其事必先利其器,如果你对于jQuery插件运用熟练的话,那么对已$.extend,你一定要去了解!,下面我们就先对$.extend来个剖析!先看看你对于$.extend的几种形式!

一、$.extend的用法

$.extend(dest,src1,src2,src3...)
$.extend({},src1,src2,src3...)    
$.extend({name:function(){}})    
$.fn.extend({name:function(){}})    
$.extend({net:{}})    
$.extend({boolean,dest,src1,src2,src3...})

1.$.extend(dest,src1,src2,src3…)

将src1,src2,src3…合并到dest中,请记住合并时,后面同名的属性会覆盖掉前面的属性,对于前面没有的属性,难就进行合并,如下:

<script type="text/javascript">
    $(function() {
        var obj = {
                name: "yyh",
                age: 26
            },
            obj1 = {
                name: "yyh1",
                age: 27
            },
            obj2 = {
                name: "yyh2",
                age: 27,
                address:"chitu"
            }
        var mergeObj = $.extend(obj,obj1,obj2);
        console.log(mergeObj)//{name: "yyh2", age: 27, address: "chitu"}
    })
</script>

2.$.extend({},src1,src2,src3…)

这个和上面的是一样的,不同只是把dest={},把src1,src2,src3合并到一个空对象中,原理同上,不在赘述!

3.$.extend({name:function(){}})

看到这个东西,你可以这么认为,这是相当于$.extend(dest,src1) 中省略了dest后变成了$.extend(src1),这样子就相当于将该src合并到调用extend方法的对象中去,也就是将src合并到jquery的全局对象中去!举个例子,我们给jquery全局对象拓展一个是否支持CSS3的方法supportCSS3:

<script type="text/javascript">
    $(function() {
        $.extend({
            supportCSS3: function() {
                var body, i, style, transition, vendor;
                body = document.body || document.documentElement;
                style = body.style;
                transition = "transition";
                vendor = ["Moz", "Webkit", "Khtml", "O", "ms"];
                transition = transition.charAt(0).toUpperCase() + transition.substr(1);
                i = 0;
                while (i < vendor.length) {
                    if (typeof style[vendor[i] + transition] === "string") {
                        return vendor[i];
                    }
                    i++;
                }
                return false;
            }
        })
        if($.supportCSS3){
            alert("该浏览器支持css33");
        }
    })
    </script>

所以像$.get,$post,$.ajax就是jquery全局对象的方法!

4.$.fn.extend({name:function(){}})

和上面的$.extend相比,如果对于js的原型对象有了解,你肯定可以知道$.fn=jQuery.prototype,也就是说这种方式是把方法拓展到jquery对象的实例中,同样来个例子:

<script type="text/javascript">
    $(function() {
        $.extend({
            supportCSS3: function() {
                var body, i, style, transition, vendor;
                body = document.body || document.documentElement;
                style = body.style;
                transition = "transition";
                vendor = ["Moz", "Webkit", "Khtml", "O", "ms"];
                transition = transition.charAt(0).toUpperCase() + transition.substr(1);
                i = 0;
                while (i < vendor.length) {
                    if (typeof style[vendor[i] + transition] === "string") {
                        return vendor[i];
                    }
                    i++;
                }
                return false;
            }
        })
        if($.supportCSS3){
            alert("该浏览器支持css33");
        }
    })
    </script>

5.$.extend({net:{}})

顾名思义,这个事在全局对象中扩展一个net命名空间,理解方式可以$.extend({name:function(){}}) 相似的。作用是干嘛?很简单假设团队有多个人,你担心推展到全局对象中会产生冲突,那么就自己独立建一个属于自己的空间,这样妈妈就在也不用担心儿子程序和别人冲突了!来个例子(如何来读取拓展的属性):

<script type="text/javascript">
    $(function() {
        $.extend({
            yyh: {
                age: 26,
                address: "chitu",
                supportCSS3: function() {
                    var body, i, style, transition, vendor;
                    body = document.body || document.documentElement;
                    style = body.style;
                    transition = "transition";
                    vendor = ["Moz", "Webkit", "Khtml", "O", "ms"];
                    transition = transition.charAt(0).toUpperCase() + transition.substr(1);
                    i = 0;
                    while (i < vendor.length) {
                        if (typeof style[vendor[i] + transition] === "string") {
                            return vendor[i];
                        }
                        i++;
                    }
                    return false;
                }

            }
        });
        //读取对应的属性
        if($.yyh.supportCSS3){
            alert("浏览器支持css3");
        }
        console.log($.yyh.age);
        console.log($.yyh.address);
    })
    </script>

5.$.extend(boolean,dest,src1,src2,src3…)

这中方式,通过boolean,来决定是否深度拷贝!这种方式想必你在很多场合也见过了,boolean默认的是false,可以省略!至于为什么这样做呢?来个例子就豁然开朗了!

<script type="text/javascript">
    $(function() {
        var obj = {
                name:{
                    nickname:"丑男孩",//外号
                    truename:"yyh",//真是姓名
                },
                age: 26
            },
            obj1 = {
                name:{
                    nickname:"小男孩",//外号
                    truename:"yyh1",//真是姓名
                },
                age:25
            },
            obj2 = {
                name:{
                    nickname:"老男孩",//外号
                    username:"uglyboy"
                },
                age: 27
            }
        var mergeObj1 = $.extend(true,obj,obj1,obj2);
        //mergeObj1={name:{nickname: "老男孩",truename: "yyh1",username: "uglyboy",age: 27}}
        var mergeObj2 = $.extend(false,obj,obj1,obj2);
        //mergeObj2={name:{nickname: "老男孩",username: "uglyboy",age: 27}}
    })
    </script>

看完上面的例子的时候,你就知道如果false的时候,后面添加的对象的obj2中没有属性truename,合并后对象就不会有truename这个属性,所以写插件的时候会在里面看到如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo1</title>
    <script src="http://libs.baidu.com/jquery/1.10.0/jquery.js"></script>
</head>

<body>
    <script type="text/javascript">
    ;(function($){
        $.fn.Plugin=function(options){
            //如果defaults是下面的形式,这里大可以不加boolean
            var defaults={
                property1:"value1",
                property2:"value2",
                property3:"value3",
                method1:function(){},
                method2:function(){},
            };
            var opt=$.extend(defaults,options);
        }
    })(jQuery)

    ;(function($){
        $.fn.Plugin=function(options){
            //如果defaults是下面的形式,亲,记得加上boolean,不然传递参数可麻烦了!
            var defaults={
                property1:{
                    property11:"value11",
                    property12:"value12",
                },
                property2:{
                    property21:"value21",
                    property22:"value22",
                },
                property3:{
                    property31:"value31",
                    property32:"value32",
                },
                method1:function(){},
                method2:function(){},
            };
            
            var opt=$.extend(true,defaults,options);
        }
    })(jQuery)

    </script>
</body>

</html>

二、jquery插件的几种形式

1.传统的插件写法,defaut没有暴露出来供外部调用(这个应该我们写插件很常用的一种方式),下面是单个实例的时候

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>无标题文档</title>
    <script src="http://libs.baidu.com/jquery/1.10.1/jquery.js"></script>
    <link rel="stylesheet" type="text/css" href="../css/reset.css">
    <style type="text/css">
    .undis {
        display: none;
    }
    
    .tab-parent {
        width: 400px;
        margin: 50px auto;
        border: 1px solid #e5e5e5;
    }
    
    .tab-hd {
        height: 45px;
    }
    
    .tab-hd li {
        padding: 15px 0;
        width: 200px;
        text-align: center;
        float: left;
        border-bottom: 1px solid #e5e5e5;
    }
    
    .tab-hd li.oncurr {
        border-color: #f60;
        color: #f60;
        font-weight: bold;
    }
    
    .tab-bd {
        padding: 20px;
        min-height: 250px;
    }
    </style>
</head>

<body>
    <div class="tab-parent" id="J_tab-parent">
        <ul class="tab-hd">
            <li class="tab-hd-item oncurr">选项卡1</li>
            <li class="tab-hd-item">选项卡2</li>
        </ul>
        <div class="tab-bd">
            <div class="tab-bd-item">选项卡1对应的内容</div>
            <div class="tab-bd-item undis">选项卡2对应的内容</div>
        </div>
    </div>
    <script type="text/javascript">
    (function($) {
        $.fn.Tab = function(options) {
            var defaults = {
                hdClass: '.tab-hd-item',
                bdClass: '.tab-bd-item'
            };
            var opts = $.extend(defaults, options),
                $hdItems = this.find(opts.hdClass),
                $bdItems = this.find(opts.bdClass);
            $hdItems.each(function(index, el) {
                var $this = $(this);
                $this.on("click", function() {
                    $this.addClass('oncurr').siblings().removeClass('oncurr');
                    $bdItems.eq(index).show().siblings().hide();
                })
            });       //如果想要支持链式写法,在这里请添加return this;  
        }
    })(jQuery);
    $(function() {
        $("#J_tab-parent").Tab();
    })
    </script>
</body>

</html>

2.default写成$.fn.default暴露出来供外部调用(这种方式的插件写法是很经常遇到的,比如jquery.cycle2.js),这个时候你应该会联想到$.fn.format在插件中的用法,这样的好处是可以让用户自定义自己的操作行为,而不用每次实例的时候都去传递同样的阐述,如下的例子:

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>无标题文档</title>
    <script src="http://libs.baidu.com/jquery/1.10.1/jquery.js"></script>
    <link rel="stylesheet" type="text/css" href="../css/reset.css">
    <style type="text/css">
    .undis {
        display: none;
    }
    
    .tab-parent {
        width: 400px;
        margin: 50px auto;
        border: 1px solid #e5e5e5;
    }
    
    .tab-hd {
        height: 45px;
    }
    
    .tab-hd li {
        padding: 15px 0;
        width: 200px;
        text-align: center;
        float: left;
        border-bottom: 1px solid #e5e5e5;
    }
    
    .tab-hd li.oncurr {
        border-color: #f60;
        color: #f60;
        font-weight: bold;
    }
    
    .tab-bd {
        padding: 20px;
        min-height: 250px;
    }
    </style>
</head>

<body>
    <div class="tab-parent" id="J_tab-parent">
        <ul class="tab-hd">
            <li class="tab-hd-item-1 oncurr">选项卡1</li>
            <li class="tab-hd-item-1">选项卡2</li>
        </ul>
        <div class="tab-bd">
            <div class="tab-bd-item-1">选项卡1对应的内容</div>
            <div class="tab-bd-item-1 undis">选项卡2对应的内容</div>
        </div>
    </div>
    <script type="text/javascript">
    (function($) {
        $.fn.Tab = function(options) {
            var opts = $.extend($.fn.Tab.defaults, options);
            return this.each(function(index, el) {
                var $hdItems = $(this).find(opts.hdClass),
                    $bdItems = $(this).find(opts.bdClass);
                $hdItems.each(function(index, el) {
                    var $this = $(this);
                    $this.on("click", function() {
                        $(this).html($.fn.Tab.format($(this).text()));
                        $this.addClass('oncurr').siblings().removeClass('oncurr');
                        $bdItems.eq(index).show().siblings().hide();
                    })
                });
            });
        }
        $.fn.Tab.defaults = {
            hdClass: '.tab-hd-item',
            bdClass: '.tab-bd-item'
        };
        $.fn.Tab.format = function(txt) {
            return '<strong>' + txt + '</strong>';
        };
    })(jQuery);
    $(function() {
        $.fn.Tab.defaults = {
            hdClass: '.tab-hd-item-1',
            bdClass: '.tab-bd-item-1'
        };
        $(".tab-parent").Tab();
    })
    </script>
</body>

</html>

和上面的$.extend相比,如果对于js的原型对象有了解,你肯定可以知道$.fn=jQuery.prototype,也就是说这种方式是把方法拓展到jquery对象的实例中,同样来个例子:

3.通过data的方式来实现jquery插件的写法(参考bootstrap.js,slidesjs)  

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>无标题文档</title>
    <script src="http://libs.baidu.com/jquery/1.10.1/jquery.js"></script>
    <link rel="stylesheet" type="text/css" href="../css/reset.css">
    <style type="text/css">
    .undis {
        display: none;
    }
    
    .tab-parent {
        width: 400px;
        margin: 50px auto;
        border: 1px solid #e5e5e5;
    }
    
    .tab-hd {
        height: 45px;
    }
    
    .tab-hd li {
        padding: 15px 0;
        width: 200px;
        text-align: center;
        float: left;
        border-bottom: 1px solid #e5e5e5;
    }
    
    .tab-hd li.oncurr {
        border-color: #f60;
        color: #f60;
        font-weight: bold;
    }
    
    .tab-bd {
        padding: 20px;
        min-height: 250px;
    }
    </style>
</head>

<body>
    <div class="tab-parent" id="J_tab-parent">
        <ul class="tab-hd">
            <li class="tab-hd-item oncurr">选项卡1</li>
            <li class="tab-hd-item">选项卡2</li>
        </ul>
        <div class="tab-bd">
            <div class="tab-bd-item">选项卡1对应的内容</div>
            <div class="tab-bd-item undis">选项卡2对应的内容</div>
        </div>
    </div>
    <script type="text/javascript">
    ;(function($, window, document, undefined) {
        var pluginName = 'Tab',
            defaults = {
                hdClass: '.tab-hd-item',
                bdClass: '.tab-bd-item'
            };

        function Plugin(element, options) {
            this.element = element;
            this.options = $.extend({}, defaults, options);
            this._defaults = defaults;
            this._name = pluginName;
            this.init();
        }
        Plugin.prototype.init = function() {
            this.$hdItems = $(this.element).find(".tab-hd-item");
            this.$bdItems = $(this.element).find(this.options.bdClass);
            var _this = this;
            this.$hdItems.each(function(index, el) {
                var $this = $(this);
                $this.on("click", function() {
                    $this.addClass('oncurr').siblings().removeClass('oncurr');
                    _this.$bdItems.eq(index).show().siblings().hide();
                })
            });
        }
        $.fn[pluginName] = function(options) {
            return this.each(function() {
                if (!$.data(this, 'plugin_' + pluginName)) {
                    return $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
                }
            })
        }

    })(jQuery, window, document);

    $(function() {
        $("#J_tab-parent").Tab()
    })
    </script>
</body>

</html>

基本的插件形式就这这三种,当然我们依然可以找到其他的方式的插件,比如私有方法的放置,还有像bootstrap.js的框架的细微的变形,万变不离其中,只要了解基本的方法,其他的都可以依葫芦画瓢!

 

交换友情链接