quexer
译自 jQuery Plugins / Authoring
看来 jQuery 你已经用得很爽了,想学习如何自己编写插件。非常好,这篇文档正适合你。用插件和方法来扩展 jQuery 非常强大,把最聪明的功能封装到插件中可以为你及团队节省大量开发时间。
开始要编写一个 jQuery 插件,需要为 jQuery.fn 对象增加一个新的函数属性,属性名就是插件的名字
jQuery.fn.myPlugin = function() { // 插件的具体内容放在这里 };等一下! 我熟悉并钟爱的 $ 哪儿去了? 它还在,只是为了确保你的插件不与其它使用 $ 的库发生冲突,有一个最佳实践: 把 jQuery 传递给 IIFE(立即调用函数),并通过它映射成 $ ,这样就避免了在执行的作用域里被其它库所覆盖。
(function( $ ) { $.fn.myPlugin = function() { // 插件的具体内容放在这里 }; })( jQuery );恩,这样好一些。 现在,在此闭包内我们可以随意用 $ 替换 jQuery。
上下文现在,已经有了外壳,可以开始编写真正的插件代码了。但在这之前,关于上下文我有话要说。在插件函数的立即作用域中,关键字 this 指向调用插件的 jQuery 对象。这是个经常出错的地方,因为有些情况下 jQuery 接受一个回调函数,此时 this 指向原生的 DOM 元素。这常常导致开发者在 jQuery 函数中对 this 关键字多作一次无必要的包装。
(function( $ ){ $.fn.myPlugin = function() { // 没有必要再作 $(this) ,因为"this"已经是 jQuery 对象了 // $(this) 与 $($('#element')) 是相同的 this.fadeIn('normal', function(){ // 在这里 this 关键字指向 DOM 元素 }); }; })( jQuery ); $('#element').myPlugin(); 基础现在理解了 jQuery 插件的上下文以后, 我们来写一个真正能做点儿事儿的插件。
(function( $ ){ $.fn.maxHeight = function() { var max = 0; this.each(function() { max = Math.max( max, $(this).height() ); }); return max; }; })( jQuery ); -- var tallest = $('div').maxHeight(); // 返回最高 div 的高度
这个简单的插件利用 .height()
来返回页面中最高 div 的高度
前面的例子返回了页面上最高 div 的一个整数值,但很多时候插件只是以某种方式修改元素集合,并把它们传给调用链的下一个方法。 这正是 jQuery 设计的漂亮之处,也是它如此流行的原因之一。为保持插件的 chainability ,必须确保插件返回 this 关键字。
(function( $ ){ $.fn.lockDimensions = 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 ); -- $('div').lockDimensions('width').css('color', 'red');
插件在立即作用域中返回了 this 关键字,保持了 chainability ,所以 jQuery 集合可以被其它方法操作,例如 .css()
。因此,若插件无需真正的返回值,你应该一直在插件函数的立即作用域中返回 this 关键字。同样,如你所想,调用插件时的参数会被传递到插件函数的立即作用域中。在上例中,字符串 “width” 成了插件函数的 type 参数。
对于那些提供许多选项、更复杂、更可配置的插件,最佳实践是提供一个默认设置,它可在插件调用时(通过 $.extend
)被扩展。这样调用插件时无需大量参数, 只要一个对象参数,内容为你希望不同于默认值的那部分设置。做法如下:
在本例中,用给定选项调用 tooltip 插件后, 默认的 location 设置被覆盖为 "left", 但 bacground-color 设置仍为默认值 "blue"。最终的设置对象看起来这样的:
{ 'location' : 'left', 'background-color' : 'blue' }这是一个非常好的方式, 可以提供一个高度可配置的插件,又不必强制开发者定义所有选项。
名称空间合理地为插件定义名称空间是插件开发中很重要的一部分。 正确的定义名称空间可以确保你的插件很难被其它插件或同一页面中的其它代码所覆盖。名称空间也可以让插件开发者的日子好过一些,因为它能帮你跟踪你的方法、事件和数据。
插件方法单个插件永远不要在 jQuery.fn 对象中声明一个以上的名称空间
(function( $ ){ $.fn.tooltip = function( options ) { // 这 }; $.fn.tooltipShow = function( ) { // 不 }; $.fn.tooltipHide = function( ) { // 好 }; $.fn.tooltipUpdate = function( content ) { // !!! }; })( jQuery );这非常不好,因为它搞乱了 $.fn 名称空间。 要修正这个问题,你应该把所有插件方法收集到一个对象定义当中,并通过传递方法名称字符串调用。
(function( $ ){ var methods = { init : function( options ) { // 这 }, show : function( ) { // 很 }, hide : function( ) { // 好 }, update : function( content ) { // !!! } }; $.fn.tooltip = function( method ) { // Method calling logic 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 ); // 调用 init 方法 $('div').tooltip(); // 调用 init 方法 $('div').tooltip({ foo : 'bar' }); -- // 调用 hide 方法 $('div').tooltip('hide'); -- // 调用 update 方法 $('div').tooltip('update', 'This is the new tooltip content!');