jquery开发:jquery插件编写类型

jQuery插件类型

jQuery插件主要分为3种类型: 
1.封装对象方法的插件(对象级别组件开发) 
这种插件是将对象方法封装起来,用于对通过选择器获取的jQuery对象进行操作,是最常见的一种插件。这类插件可以发挥出jQuery选择器的强大优势。 
即挂在jQuery原型下的方法,这样通过选择器获取的jQuery对象实例也能共享该方法,也称为动态方法(实例方法)

$.fn.myPlugin = function(){
    //do something
}
//这里$.fn===$.prototype
//例如:addClass()、attr()等,需要创建实例来调用
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

2.封装全局函数的插件(类级别组件开发) 
可以将独立的函数加到jQuery命名空间之下,例如jQuery.noConflict()方法就是jQuery内部作为全局函数的插件附加到内核上去的。 
即给jQuery命名空间下添加新的全局函数,也称为静态方法

jQuery.myPlugin = function(){
    //do something
}
//例如:$.Ajax()、$.extend()
   
   
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

3.选择器插件 
个别情况下,会需要用到选择器插件。

插件的基本要点

  • jQuery插件的文件名推荐命名为jQuery.[插件名].js,以免和其他JavaScript库插件混淆。
  • 所有的对象方法都应该附加到jQuery.fn对象上,而所有的全局函数都应该附加到jQuery对象本身上
  • 在插件内部,this指向的是当前通过选择器获取到的jQuery对象。
  • 可以通过this.each来遍历所有元素
  • 所有的方法或函数插件,都应当以分号结尾,否则压缩的时候可能出现问题。为了更加稳妥些,甚至可以在插件头部先加上一个分号,以免他人的不规范代码给插件带来影响。
  • 插件应该返回一个jQuery对象,以保证插件的可链式操作。

常见插件形式

//注意为了更好的兼容性,开始前有个分号
;(function($){//此处将$作为匿名函数的形参
    //这里放置代码,可以使用$作为jQuery的缩写别名
    //定义一个局部变量foo,仅函数内部可以访问,外部无法访问
    var foo;
    var bar = function(){
    //在匿名函数内部的函数都可以访问foo,即便是在匿名函数的外部调用bar()的时候,也可以在bar()的内部访问到foo.但在匿名函数的外部直接访问foo是做不到的
    }
    $.BAR = bar;
    //这个语句让匿名函数内部的函数bar()逃逸到全局可访问的范围内,这样就可以在匿名函数的外部调用,jQuery.BAR()来访问内部定义的函数bar(),并且内部函数bar()也能访问匿名函数内的变量foo
})(jQuery);//这里将jQuery作为实参传递给匿名函数
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

插件开头不加分号的问题

举个例子:

<script type="text/javascript">
    var fn = function(){
        console.log("我的结尾没有加分号");
    }
    (function(){
        console.log("上面函数结尾没有加分号,导致我不能正确执行");
    })();
    </script>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里写图片描述 
特别说明: 由上面的例子可以看出,在插件前加分号还是很有必要的。

插件中的闭包

关于闭包,ECMAScript对其进行了这样的定义:允许使用内部函数(即函数定义和函数表达式位于另一个函数的函数体内),而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数,当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。即内部函数会在外部函数返回后被执行。而当这个内部函数执行时,它让然必须访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明的值是外部函数返回时的值,但也会受到内部函数的影响。

我们利用闭包可以访问和修改包含函数中的局部变量 
利用闭包的特性,既可以避免内部临时变量影响全局空间,又可以在插件内部继续使用$作为jQuery的别名.

提供插件的默认选项

插件应该会有一些选项是可以让开发者自己根据需要设置的,所以提供恢复默认选项是以有必要的。你可以通过jQuery的extend功能来设置这些选项:

var defaults = {//默认配置参数
        'container' : '#container',//容器
        'sections' : '.section',//子容器
        'easing' : 'ease',//特效方式,ease-in,ease-out,linear
        'duration' : 1000,//每次动画执行的时间
        'pagination' : true,//是否显示分页
        'loop' : false,//是否循环
        'keyboard' : true,//是否支持键盘
        'direction' : 'vertical',//滑动的方向horizontal,vertical,
    };

opts = $.extend({}, defaults , options||{});
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

jQuery提供了两个用于扩展jQuery功能的方法:jQuery.extend()和jQuery.fn.extend().这两个方法都接受一个参数,类型为Object。Object对象的”名/值对”分别代表”函数或方法名/函数主体”. 
特别说明: $.extend()方法的第一个参数是一个空对象,而不是默认参数defaults,这里的原因是为了保护默认参数值不会被用户自定义参数所修改。

jQuery.extend()用法

jQuery.extend()方法除了可以用于扩展jQuery对象外,还可以用于扩展已有的object对象。 
将对象的属性添加给jQuery对象 
Demo:

<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript">
$(function(){
    var obj1 = {
        apple:0,
        banana:{weight:52,price:100},
        cherry:97
    };
    jQuery.extend(obj1);//这样写是将obj1对象的属性添加给jQuery对象
    console.log(jQuery.apple);//0
    console.log(jQuery.banana);//Object {weight: 52, price: 100}
    console.log(jQuery.cherry);//97
});
</script>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript">
/*
这个例子是合并obj1对象和obj2对象,修改并返回obj1对象
 */
$(function(){
    var obj1 = {
        name:"lisi",
        job:"worker",
        age:22
    };
    var obj2 = {
        name:"wangwu",
        age:100,
        address:"大连"
    };
    $.extend(obj1,obj2);//默认第一个参数为false,即进行浅拷贝
    console.log(obj1);//Object {name: "wangwu", job: "worker", age: 100, address: "大连"}
});
</script>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

浅拷贝:

<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript">
$(function(){
    var obj1 = {
        apple:0,
        banana:{weight:52,price:100},
        cherry:97
    };
    var obj2 = {
        banana:{price:200},
        durian:100
    };
    var obj = $.extend(obj1,obj2);
    var obj1 = $.extend(false,obj1,obj2);//默认第一个参数是false,浅拷贝
    console.log(JSON.stringify(obj));//{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
    console.log(JSON.stringify(obj1));
    //从输出的结果可以看出,banana这个key值被替换掉了
});
</script>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

深拷贝:也会对嵌套子对象进行递归合并

<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript">
$(function(){
    var obj1 = {
        apple:0,
        banana:{weight:52,price:100},
        cherry:97
    };
    var obj2 = {
        banana:{price:200},
        durian:100
    };
    var obj = $.extend(true,obj1,obj2);//第一个参数true表示深拷贝
    console.log(JSON.stringify(obj));//{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}
//深拷贝是进行递归合并,对已有属性值进行覆盖,没有的属性进行增加
</script>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

深拷贝和浅拷贝结果对比:

//深拷贝
{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}
//浅拷贝
//{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
   
   
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

浅拷贝的结果直接将banana的值进行了替换,深拷贝对banana的值进行合并修改,不是简单的直接替换。 
jQuery.extend()方法经常被用于设置插件方法的一系列默认参数 
Demo:

<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript">
$(function(){
    function fn(options){
        options = $.extend({
            name:"bar",
            length:5,
            dataType:"xml"/*默认参数设置*/
        },options);
        return options;
    }
    console.log(fn({name:"a",length:6,dataType:"json"}));//Object {name: "a", length: 6, dataType: "json"}
    console.log(fn({name:"b",length:7}));//Object {name: "b", length: 7, dataType: "xml"}
    console.log(fn({name:"c"}));//Object {name: "c", length: 5, dataType: "xml"}
    console.log(fn());//Object {name: "bar", length: 5, dataType: "xml"}
});
</script>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

我们在调用fn()方法的时候,在传递的参数options对象中设置了相应的值,那么就使用设置的值,否则就使用默认值。通过使用$.extend()方法,可以很方便地用传入的参数来覆盖默认值。

jQuery插件编写

jQuery.color插件

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>jQuery.color插件</title>
    <style type="text/css">
        .red{
            color: red;
        }
    </style>
</head>
<body>
<div class="red">red</div>
<div class="blue" style="color: blue;">blue</div>
<div class="yellow" style="color:yellow;">yellow</div>
<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript" src="jQuery.color.js"></script>
<script type="text/javascript">
//插件应用
$(function(){
    console.log($("div").color("red"));
});
</script>
</body>
</html>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

jQuery.color.js

;(function($){
    $.fn.extend({
        "color":function(value){
            return this.css("color",value);//设置字体颜色值
        }
    });
})(jQuery);
/*
这里给这个方法提供一个参数value,如果调用方法的时候传递了value这个参数,那么就是用这个值来设置
字体颜色,否则就是获取匹配元素的字体颜色的值
 */
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

面向对象的插件开发

这里有一个疑问:为什么要有面向对象的方式来开发插件?为了解决这个问题,也查了很多资料,最后明白原因。 
因为如果不这样,你可能需要一个方法的时候就去定义一个function,当需要另外一个方法的时候,再去随便定义一个function,同样,需要一个变量的时候,毫无规则地定义一些散落在代码各处的变量。 
还是老问题,不方便维护,也不够清晰。当然,这些问题在代码规模较小时是体现不出来的。 
如果将需要的重要变量定义到对象的属性上,函数变成对象的方法,当我们需要的时候通过对象来获取,一来方便管理,二来不会影响外部命名空间,因为所有这些变量名还有方法名都是在对象内部。 
采用面向对象的方式开发,有利于更好地维护和理解插件,以后要加新功能新方法,只需向对象添加新变量及方法即可,然后在插件里实例化后即可调用新添加的东西。

Demo:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title></title>
    <style type="text/css">
    a{
        display: block;
        margin-bottom: 10px;
        text-decoration: none;
    }
    </style>
</head>
<body>
<a href="www.123.com">百度一下</a>
<a href="www.456.com">谷歌一下</a>
<a href="www.789.com">必应一下</a>
<script type="text/javascript" src="../jquery-1.11.2.min.js"></script>
<script type="text/javascript">
var changeStyle = function(ele,options){
    this.ele = ele;
    this.defaults = {
        'color':'red',
        'fontSize':'30px'
    };
    this.settings = $.extend({},this.defaults,options);
};
changeStyle.prototype = {
    doChange:function(){
        return this.ele.css({
            'color':this.settings.color,
            'fontSize':this.settings.fontSize
        });
    }
};
//给jQuery的原型添加方法,即添加实例方法
// $.fn.extend({
//  //styleChange就是我们定义的插件名称
//  styleChange:function(options){
//      var obj = new changeStyle(this,options);
//      return obj.doChange();
//  }
// });
$.fn.styleChange = function(options){
    var obj = new changeStyle(this,options);
        return obj.doChange();
};
$("a").styleChange({
    'color':'green',
    'fontSize':'20px'
});
</script>
</body>
</html>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

防止全局变量污染

不仅仅是jQuery插件的开发中需要注意这个问题,我们在写任何JS代码时都应该注意的一点是不要污染全局变量。随着代码量的增多,如果有意无意在全局范围内定义一些变量的话,最后很难维护,也容易跟别人写的代码有冲突。 
举个例子:你在代码中向全局window对象添加了一个变量status用于存放状态,同时页面中引用了另一个别人写的库,也向全局添加了这样一个同名变量,最后的结果肯定不是你想要的。所以不到万不得已,一般我们不会将变量定义成全局的。 
解决方法:使用自执行的匿名函数包裹插件代码,这样就可以完全放心,安全地将它用于任何地方了,绝对没有冲突。我们知道JavaScript中无法用花括号方便地创建作用域,但函数却可以形成私有作用域,域内的代码是无法被外界访问的。如果我们将自己的代码放入一个函数中,那么就不会污染全局命名空间,同时不会和别的代码冲突。

<script type="text/javascript">
//将定义的插件放在一个自执行的匿名函数中
(function($,window,undefined){
    var changeStyle = function(ele,options){
    this.ele = ele;
    this.defaults = {
        'color':'red',
        'fontSize':'30px'
    };
    this.settings = $.extend({},this.defaults,options);
};
changeStyle.prototype = {
    doChange:function(){
        return this.ele.css({
            'color':this.settings.color,
            'fontSize':this.settings.fontSize
        });
    }
};
$.fn.styleChange = function(options){
    var obj = new changeStyle(this,options);
        return obj.doChange();
};
$("a").styleChange({
    'color':'green',
    'fontSize':'20px'
});
})(jQuery,window,undefined);
</script>
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

这样写还有一个好处就是:自调用匿名函数里面的代码会在第一时间执行,页面准备好过后,上面的代码就将插件准备好了,以方便在后面的代码中使用插件。 
在上面的代码中还要注意一点:我们将jQuery对象、window对象以及undefined作为实参传递给了匿名函数。 
这样window等系统变量在插件内部就有了一个局部的引用,可以提高其访问速度,有助于性能的提升(我们都知道:全局变量的查找是最慢的)。 
参考博文: 
创建更好jQuery插件的10个建议 
jQuery插件开发模式 
深入理解jQuery插件开发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值