jQuery插件的点点滴滴
说起jQuery插件,很多人的脑海种已经有了一定的雏形,仿佛感觉仅仅就是那样子,事实呢?当你看了Bootstrap.js,品读了slidesjs,观摩了jquery.cycle2.js,不禁发现,原来插件的世界千变万化,细微之处总是不容易让人发觉,世界那么大,那么我们就一起去看看它到底长什么样子?
工欲善其事必先利其器,如果你对于jQuery插件运用熟练的话,那么对已$.extend,你一定要去了解!,下面我们就先对$.extend来个剖析!先看看你对于$.extend的几种形式!
一、$.extend的用法
1 $.extend(dest,src1,src2,src3...) 2 $.extend({},src1,src2,src3...) 3 $.extend({name:function(){}}) 4 $.fn.extend({name:function(){}}) 5 $.extend({net:{}}) 6 $.extend({boolean,dest,src1,src2,src3...})
$.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>
$.extend({},src1,src2,src3...)
这个和上面的是一样的,不同只是把dest={},把src1,src2,src3合并到一个空对象中,原理同上,不在赘述!
$.extend({name:function(){}})
看到这个东西,你可以这么认为,这是相当于$.extend(dest,src1) 中省略了dest后变成了$.extend(src1),这样子就相当于将该src合并到调用extend方法的对象中去,也就是将src合并到jquery的全局对象中去!举个例子,我们给jquery全局对象拓展一个是否支持CSS3的方法supportCSS3:
1 <script type="text/javascript"> 2 $(function() { 3 $.extend({ 4 supportCSS3: function() { 5 var body, i, style, transition, vendor; 6 body = document.body || document.documentElement; 7 style = body.style; 8 transition = "transition"; 9 vendor = ["Moz", "Webkit", "Khtml", "O", "ms"]; 10 transition = transition.charAt(0).toUpperCase() + transition.substr(1); 11 i = 0; 12 while (i < vendor.length) { 13 if (typeof style[vendor[i] + transition] === "string") { 14 return vendor[i]; 15 } 16 i++; 17 } 18 return false; 19 } 20 }) 21 if($.supportCSS3){ 22 alert("该浏览器支持css33"); 23 } 24 }) 25 </script>
所以像$.get,$post,$.ajax就是jquery全局对象的方法!
$.fn.extend({name:function(){}})
和上面的$.extend相比,如果对于js的原型对象有了解,你肯定可以知道$.fn=jQuery.prototype,也就是说这种方式是把方法拓展到jquery对象的实例中,同样来个例子:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>demo1</title> 6 <script src="http://libs.baidu.com/jquery/1.10.0/jquery.js"></script> 7 </head> 8 <body> 9 <button id="btn1">点击</button> 10 <script type="text/javascript"> 11 $(function() { 12 $.fn.extend({ 13 say: function() { 14 alert("我是丑男孩"); 15 return this;//为什么加this,jquery的链式写法,你懂的! 16 } 17 }); 18 $("#btn1").on("click",function(){ 19 $(this).say().hide(); 20 }) 21 22 }) 23 </script> 24 </body> 25 </html>
$.extend({net:{}})
顾名思义,这个事在全局对象中扩展一个net命名空间,理解方式可以$.extend({name:function(){}}) 相似的。作用是干嘛?很简单假设团队有多个人,你担心推展到全局对象中会产生冲突,那么就自己独立建一个属于自己的空间,这样妈妈就在也不用担心儿子程序和别人冲突了!来个例子(如何来读取拓展的属性):
1 <script type="text/javascript"> 2 $(function() { 3 $.extend({ 4 yyh: { 5 age: 26, 6 address: "chitu", 7 supportCSS3: function() { 8 var body, i, style, transition, vendor; 9 body = document.body || document.documentElement; 10 style = body.style; 11 transition = "transition"; 12 vendor = ["Moz", "Webkit", "Khtml", "O", "ms"]; 13 transition = transition.charAt(0).toUpperCase() + transition.substr(1); 14 i = 0; 15 while (i < vendor.length) { 16 if (typeof style[vendor[i] + transition] === "string") { 17 return vendor[i]; 18 } 19 i++; 20 } 21 return false; 22 } 23 24 } 25 }); 26 //读取对应的属性 27 if($.yyh.supportCSS3){ 28 alert("浏览器支持css3"); 29 } 30 console.log($.yyh.age); 31 console.log($.yyh.address); 32 }) 33 </script>
$.extend(boolean,dest,src1,src2,src3...)
这中方式,通过boolean,来决定是否深度拷贝!这种方式想必你在很多场合也见过了,boolean默认的是false,可以省略!至于为什么这样做呢?来个例子就豁然开朗了!
1 <script type="text/javascript"> 2 $(function() { 3 var obj = { 4 name:{ 5 nickname:"丑男孩",//外号 6 truename:"yyh",//真是姓名 7 }, 8 age: 26 9 }, 10 obj1 = { 11 name:{ 12 nickname:"小男孩",//外号 13 truename:"yyh1",//真是姓名 14 }, 15 age:25 16 }, 17 obj2 = { 18 name:{ 19 nickname:"老男孩",//外号 20 username:"uglyboy" 21 }, 22 age: 27 23 } 24 var mergeObj1 = $.extend(true,obj,obj1,obj2); 25 //mergeObj1={name:{nickname: "老男孩",truename: "yyh1",username: "uglyboy",age: 27}} 26 var mergeObj2 = $.extend(false,obj,obj1,obj2); 27 //mergeObj2={name:{nickname: "老男孩",username: "uglyboy",age: 27}} 28 }) 29 </script>
看完上面的例子的时候,你就知道如果false的时候,后面添加的对象的obj2中没有属性truename,合并后对象就不会有truename这个属性,所以写插件的时候会在里面看到如下:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>demo1</title> 6 <script src="http://libs.baidu.com/jquery/1.10.0/jquery.js"></script> 7 </head> 8 9 <body> 10 <script type="text/javascript"> 11 ;(function($){ 12 $.fn.Plugin=function(options){ 13 //如果defaults是下面的形式,这里大可以不加boolean 14 var defaults={ 15 property1:"value1", 16 property2:"value2", 17 property3:"value3", 18 method1:function(){}, 19 method2:function(){}, 20 }; 21 var opt=$.extend(defaults,options); 22 } 23 })(jQuery) 24 25 ;(function($){ 26 $.fn.Plugin=function(options){ 27 //如果defaults是下面的形式,亲,记得加上boolean,不然传递参数可麻烦了! 28 var defaults={ 29 property1:{ 30 property11:"value11", 31 property12:"value12", 32 }, 33 property2:{ 34 property21:"value21", 35 property22:"value22", 36 }, 37 property3:{ 38 property31:"value31", 39 property32:"value32", 40 }, 41 method1:function(){}, 42 method2:function(){}, 43 }; 44 45 var opt=$.extend(true,defaults,options); 46 } 47 })(jQuery) 48 49 </script> 50 </body> 51 52 </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>
多个实例的时候
<!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> <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); 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.addClass('oncurr').siblings().removeClass('oncurr'); $bdItems.eq(index).show().siblings().hide(); }) }); }); } })(jQuery); $(function() { $(".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>
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的框架的细微的变形,万变不离其中,只要了解基本的方法,其他的都可以依葫芦画瓢!