JQuery插件开发学习
插件是JQuery强大之处的体现,把最聪明的功能封装到插件中,可以为你及你的团队节省大量开发时间.
编写一个JQuery插件,在于给JQuery.fn加入新的功能属性,此处添加的对象属性名称就是你插件的名称
js代码
jQuery.fn.myPlugin = function(){
//你自己的插件代码
}
可以看到,好像$符号不见了。它仍然存在,为了确保你的插件不与其他使用$的库发生冲突。有一个最佳实践: 把jQuery传递给IIFE (立即调用函数) (自我执行的封闭程序,jQuery在此程序中映射成$符号), 并通过它映射成$, 这样就避免了在执行的作用域中被其他库所覆盖.
js代码 (function($){ $.fn.myPlugin = function(){ //你自己的插件代码 }; })(jQuery)
在这个封闭的程序中,我们可以无限制的使用$符号来表示jQuery函数
上下文
现在,整个外壳已经写好,就可以开始编写真正的插件代码了. 在插件的范围内,this 关键字代表了这个插件将要执行的jQuery对象. 这里要特别注意一下, 因为在其他包含callback的jQuery函数中,this关键字代表了原生的DOM元素. 这容易导致开发人员误将this关键字无谓的包含在jQuery中,如下:
(function($){ $.fn.myPlugin = function(){ //此处没有必要将this包在$号中,如$(this),因为this已经是一个jQuery对象 //$(this)等同于 $($('#element')); this.fadeIn('normal', function(){ // 在这个fadeIn函数内部, this 关键字指向DOM对象 });
}; })(jQuery);
基础知识点
写一个简单的插件,来做一些事情
js 代码 (function($){ $.fn.maxHeight = function(){ var max = 0; this.each(function(){ max = Math.max(max,$(this).height()); }); return max; } })(jQuery); 调用这个jquery plugin var height = $('div').maxHeight(); //返回页面上所有div元素中,高度最大的那个div元素的高度
实现Chainability
上面的方法中,返回了页面上最高div的高度,是个整数值. 但是,有的时候,jQuery插件的作用只是修改或者获取页面上元素的属性值,返回一个jQuery对象,然后把它传递给调用链的下一个方法。据说这也正是jQuery设计好的地方所在。 那么,为了确保jQuery插件的chainability, 必须确保这个jQuery插件返回this关键字
现在我们来写一个例子,这个jQuery插件,传入一个type参数 (width或者height),返回插件内部的this, 也就是jQuery对象
(function($){ $.fn.getDimension = function(type){ return this.each(function(){ var $this = $(this); if(!type && type == 'width'){ $this.width($this.width()); } if(!type && type == 'height'){ $this.height($this.height()); } }); }; })(jQuery); 调用这个jQuery plugin $('div').getDimension('width').css('color','red');
一定要特别注意这种写法,因为jQuery plugin 经常这样使用,return this.each(function(){ // do something }), 这样,来返回jQuery对象。
在这种使用中,由于这个jQuery插件返回了this关键字,这样返回值,依然可以直接使用其他jQuery方法,如css, 实现了chainability.
所以,在jQuery插件中,如果不需要返回值,那么,你应该总是在其作用范围内返回this关键字(jQuery对象)
默认设置和选项
jQuery插件,还有一种是传递更多选项options参数,提供许多选项,更复杂,更可配置的插件。 这种使用,最佳的实践是提供一个默认配置, 它可以在插件调用时 (通过$.extend)被扩展.
这样,调用插件时,无需大量参数。 只需要一个对象参数,内容为你希望不同于默认值的那部分设置. 比如下面的例子:
(function($){ $.fn.tooltip = function(options){ var settings = $.extend( { 'location' : 'top', 'background-color' : 'blue' }, options); return this.each(function(){ //tooltip plugin code }); }; })(jQuery); 调用tooltip这个jQuery插件 $('div').tooltip( { 'location' : 'left' } );
在这个例子中,用给定选项调用 tooltip 插件后, 默认的 location 设置被覆盖为 "left", 但 bacground-color 设置仍为默认值 "blue"。最终的设置对象看起来这样的:
{ 'location' : 'left', 'background-color' : 'blue' }
这是一个非常好的方式, 可以提供一个高度可配置的插件,又不必强制开发者定义所有选项。
名称空间
首先要明白什么是jQuery插件中的名称空间,是这样的,比如jQuery插件 $.fn.tooltip, tooltip 就是这个插件的名称空间。 正确的名称空间非常重要,它可以确保你的插件很难被其他插件或同一页面中的其他代码所覆盖。
这里有个原则,就是在任何情况下,一个单独的插件,都不应该在jQuery.fn对象里有多个名称控件,比如 以下做法是完全不推荐的:
(function($){ $.fn.tooltip = function(options){ }; $.fn.tooltipShow = function(){ }; $.fn.tooltipHide = function(){ }; $.fn.tooltipUpdate = function(content){ }; })(jQuery);
这种写法是不被鼓励的,因为它 $.fn使 $.fn的名称空间搞的混乱。 正确的方法是,你需要把所有插件方法收集到一个对象定义中,并通过传递方法名称字符串调用:(funcvar methods init : function(options){
show : function(){ }, hide : function(){ }, update : function(content){ } };
$.fn.tooltip = function(method){
//方法调用
if(methods[method]){
return methods[method].apply(this,Array.prototype.slice.call(arguments,1));
}
else if (typeof method === 'object' || !method)
{
return methods.init.apply(this,arguments);
}
else
{
$.error('Method' + method + 'does not exist on jQuery.tooltip');
}
}; })(jQuery);
//调用该jquery插件中的 init方法
$('div').tooltip();
//调用该jquery插件中的 init方法
$('div').tooltip(
{foo : 'bar'}
);
//调用该jquery插件中的 hide方法
$('div').tooltip('hide');
//调用该jquery插件中的 Update方法
$('div').tooltip('update','This is the new tooltip content!');
特别注意这种类型的插件结构, 它允许你封装所有的方法在父包中,通过传递该方法的字符串名称和额外的此方法需要的参数来调用它们。
这种方法的封装和架构类型是jQuery插件社区的标准, 它被无数的插件在使用。 包括jQueryUI中的插件和widgets.
事件
bind方法有个特性,它支持为绑定事件定义名称空间。如果你的插件要绑定事件,最好为其定义名称空间。 这样的话,后面你想解除事件绑定unbind时,就不会影响到相同事件类型上的其他已绑定事件。
需要为事件定义名称空间,把".<namespace >"附加到要绑定的事件类型后面就可以。
(function($){ var methods = { init: function(options){ return this.each(function(){ $(window).bind('resize.tooltip', methods.reposition); }); }, destroy : function() { return this.each(function(){ $(window).unbind('.tooltip'); }); }, reposition : function(){ }, show : function(){ }, hide : function(){ }, update : function(content){ } }; $.fn.tooltip = function( method ) { if ( methods[method] ) { return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); } else if ( typeof method === 'object' || ! method ) { return methods.init.apply( this, arguments ); } else { $.error( 'Method ' + method + ' does not exist on jQuery.tooltip' ); } }; })(jQuery); //调用这个jQuery插件 $('#fun').tooltip(); //解除绑定 unbind $('#fun').tooltip('destory');
在这个例子中,当tooltip被init方法初始化的时候,它把reposition方法绑定到window对象的resize事件上,名称空间为'tooltip'.
如果开发者哪一天想要销毁对象,可以把插件的名称空间(即 "tooltip")传给unbind方法,以便解除本插件对所有事件的绑定.
这让我们可以安全地解除本插件的事件绑定,避免意外影响插件之外绑定的事件.
数据
插件开发中,你可能经常需要维护状态,或检查你的插件是否已经在给定元素上做过初始化。 jQuery data方法