jQuery插件编写入门【译】

先贴上原文地址:How to Create a Basic Plugin
英文好的就去看原文吧,我这英语四级的渣渣水平,如有译的不好的地方,请各位看官多多包涵,欢迎批评指正。
下面是正文,各位将就着看吧^_^


有时候,你想用代码实现一个能够使用的功能。举个栗子,可能你想要一个单一的方法去调用一个jQuery选择器并且对其进行一系列的操作。也可能你写了一个非常有用的工具函数,然后你想把它方便地移植到其他项目当中。当你遇到这些情况时,是时候写个插件了,骚年!

jQuery是怎样工作的:jQuery对象方法和工具方法

在我们开始写自己的插件之前,我们必须先简单了解一下jQuery是怎样工作的。看下面这段代码:

1
$( "a" ).css( "color", "red" );

这是段基础的jQuery代码,但是你知道在这背后发生了什么吗?无论什么时候你用$函数选择元素,都会返回一个jQuery对象。这个对象包含了所有你用过的方法(.css(),.click()等等)和所有匹配你选择器的元素。jQuery对象从$.fn对象中获得这些方法,这个对象(译注:指$.fn对象)包含了所有jQuery的对象方法,所以如果我们要写自己的方法,也要包含这些方法。

此外jQuery的工具方法$.trim()用来删除用户输入的字符串中所有的前导和后置空格。工具方法是直接依附在$函数本身上的方法。当你要对你获取到的DOM元素集进行一些在jQuery的API中没有提供的操作时,你可能想要去写一个工具方法插件。

感觉翻的有点乱,自己概括下:jQuery对象方法就是挂在$.fn上的方法,可通过$("#id").yourmethod();这种形式调用;工具方法就是挂在$上的方法,通过$.yourmethod();这种形式调用

基础插件编写

接下来我们要编写一个能使选取到的元素的文本颜色变为绿色的插件。我们要做的就是添加一个greenify函数到$.fn上,这样就能像其它的jQuery对象方法一样使用了。

1
2
3
4
5
$.fn.greenify = function() {
this.css( "color", "green" );
};

$( "a" ).greenify(); // Makes all the links green.

注意使用.css(),另一个方法,我们使用this,而不是$( this )。这是因为我们的greenify方法与.css()是同一个对象的方法。

链式

现在,我们编写的插件已经能够正常工作了,但是如果想要让它在现实世界中存活下来的话,还得做点什么。jQuery有一个特性是链式,你可以对一个选择器链接上五六个操作(译注:即$("#id").css("color","blue").show();这种操作)。这个特性是通过让所有的jQuery对象方法返回原始的jQuery对象来完成的(但是有一些例外,如:.width()无参调用时,返回的是选中元素的宽度,这时是不可链式的)。要使我们的插件方法能够被链式调用需要一行代码:

1
2
3
4
5
6
$.fn.greenify = function() {
this.css( "color", "green" );
return this;
}

$( "a" ).greenify().addClass( "greenified" );

需要注意的是链式的概念并不适用于jQuery的工具方法,比如:.trim()

链式是挺重要的一点,它可以让我们写的插件更好的融入到jQuery本身所提供的方法或者其它插件方法之中。

保护$别名和添加作用域

$变量在JavaScript库中非常常用,所以如果你在使用jQuery的同时还使用别的库,你就会通过jQuery.noConflict()来使jQuery不使用$(译注:即释放jQuery对$变量的控制,能使其它使用$变量的库正常工作)。然而,这会破坏我们的插件,因为我们是基于$是jQuery的别名这一假设上进行编写的。为了使我们的插件能够与其它插件一起使用,并且仍然用$来做jQuery的别名,我们需要把代码放到一个立即调用的函数表达式中,然后传递jQuery,并把参数定义为$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(function ( $ ) {

$.fn.greenify = function() {
this.css( "color", "green" );
return this;
};

$.ltrim = function( str ) {
return str.replace( /^\s+/, "" );
};

$.rtrim = function( str ) {
return str.replace( /\s+$/, "" );
};

}( jQuery ));

此外,立即调用函数的主要目的是允许我们拥有自己的私有变量。假设我们想要一个不同的绿色,并且我们想要把它存在一个变量中。

1
2
3
4
5
6
7
8
9
10
(function ( $ ) {

var shade = "#556b2f";

$.fn.greenify = function() {
this.css( "color", shade );
return this;
};

}( jQuery ));

最小化插件的足迹

在写插件时只占用$.fn的一个接口(译注:原文为slot,意为「插槽」,但是感觉翻译成「接口」更符合平时的习惯,后面就用统一使用「接口」)是一个很好的实践。这会减少你的插件被重写的可能,以及你的插件覆盖别的插件的可能。换句话说,这样是不好的:

1
2
3
4
5
6
7
8
9
10
11
(function( $ ) {

$.fn.openPopup = function() {
// Open popup code.
};

$.fn.closePopup = function() {
// Close popup code.
};

}( jQuery ));

使用一个接口,用参数来控制接口的具体实现会好很多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(function( $ ) {

$.fn.popup = function( action ) {

if ( action === "open") {
// Open popup code.
}

if ( action === "close" ) {
// Close popup code.
}

};

}( jQuery ));

使用each()方法

典型的jQuery对象将包含任意数量的DOM元素的引用,这就是为什么jQuery对象经常被称为集合的原因。如果你想要对特定的元素做任何操作(比如获取一个data属性,计算具体的位置)那么你需要用.use()来遍历元素。

1
2
3
4
5
6
7
$.fn.myNewPlugin = function() {

return this.each(function() {
// Do something to each element here.
});

};

注意,这里我们返回.each()的结果而不是返回this。因为.each()已经是可链式的,它会返回this。到目前为止,这是一个比我们做过的更好的维护可链式的方式。

接受选项

随着你的插件变得越来越复杂,使你的插件可通过接受选项来自定义是一个好主意。做这个最简单的方法,特别是有很多的选项,是用对象字面量。让我们改变我们的greenify插件,使其接受一些选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(function ( $ ) {

$.fn.greenify = function( options ) {

// 这是拥有默认选项最简单的方法。
var settings = $.extend({
// 这些是默认选项。
color: "#556b2f",
backgroundColor: "white"
}, options );

// 基于settings变量来进行设置
return this.css({
color: settings.color,
backgroundColor: settings.backgroundColor
});

};

}( jQuery ));

用法示例:

1
2
3
$( "div" ).greenify({
color: "orange"
});

color的默认值#556b2f通过$.extend()被覆盖成橙色。

放在一起

这是一个使用我们已经讨论过的技术完成的小插件的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(function( $ ) {

$.fn.showLinkLocation = function() {

this.filter( "a" ).each(function() {
var link = $( this );
link.append( " (" + link.attr( "href" ) + ")" );
});

return this;

};

}( jQuery ));

// 用法示例:
$( "a" ).showLinkLocation();

这个方便的插件将所有在集合中的a标签的内容后边插入了写在括号中的href属性。

1
2
3
4
5
<!-- 调用插件之前: -->
<a href="page.html">Foo</a>

<!-- 调用插件之后: -->
<a href="page.html">Foo (page.html)</a>

我们的插件可以优化:

1
2
3
4
5
6
7
8
9
10
11
12
13
(function( $ ) {

$.fn.showLinkLocation = function() {

this.filter( "a" ).append(function() {
return " (" + this.href + ")";
});

return this;

};

}( jQuery ));

我们使用.append()方法接受回调函数的能力,这个回调函数的返回值会决定追加什么到集合中的每个元素后面。另外我们也没有使用.attr()方法去获取href属性,因为本地的DOM API可以让我们用href轻松访问该属性。


呼~~终于算是完成了,果然我这英语水平翻译起来还是有点困难啊,有些翻译出来不通顺的地方我都意译了。如果你在阅读中发现还有不通顺或难以理解的地方,欢迎指出^_^(请原谅我捉急的英语吧OTL)

最后,再总结下:
jQuery有两种方法:对象方法工具方法。对象方法就是挂在$.fn上的方法,可通过$("#id").yourmethod();这种形式调用;工具方法就是挂在$上的方法,通过$.yourmethod();这种形式调用。因为我们写的插件一般都会操作DOM元素,所以插件都会挂在$.fn上,即用第一种形式,使之成为jQuery的对象方法。
注意点:

  • 插件方法应返回this,使之能够链式编写。
  • 对外提供的接口应尽量少,即减少挂在$.fn上的函数。
  • 要能接受选项,以提供自定义功能。