七、Extending jQuery with Plug-in
jQuery是很容易通过插件来扩展它的的功能的,在http://plugins.jquery.com上可以找到很多这样的插件。
你可以很容易地编写自己的插入,诀窍就是认识到jQuery.fn是所有jQuery对象的原型对象,在这个原型对象上增加一个方法,那个方法就成为了jQuery对象的方法。如:
jQuery.fn.println=function(){
var msg=Array.prototype.join.call(arguments," ");
return this.each(function(){jQuery(this).append(document.createTextNode(msg)).append("<br/>");});
};
在编写你的扩展的时候,如果遵循模块化编码实践以及jQuery特有的约定,你可以把你的扩展成为一个插件并且和别人分享。以下是一些你需要了解的jQuery约定:
a. 不要依赖$标识符:也许包含的页面调用了jQuery.noConflict(),$不再是jQuery的简短表示了。在很短的插件中,你可以使用jQuery代替$。如果插件很长,你可以把他们包装到一个匿名函数里面并立即调用。
惯常的做法是把$作为匿名函数的参数名,把jQuery作为实参传进去,即:
(function($){ //一个匿名函数,参数名为$
...//put your plugin code here
}(jQuery));//使用jQuery对象作为参数调用匿名函数
b. 如果插件方法本身没有返回值,确保返回一个jQuery对象本身,这样可以在一个方法链中使用。
c. 如果插件方法有多个参数,请允许用户传递一个参数集合对象,就像animate()和ajax()方法一样。
d. 不用污染jQuery方法的命名空间,空间中的方法数越少越好。最好一个插件只有一个方法在jQuery.fn上,这个方法第一个参数为字符串,这个字符串是另一个函数的名字,其他的参数作为这个函数的参数传递到这个函数里。此时这个方法的名字最好和插件的名字一样。如果实在不能写成一个方法,那么这些方法的命名最好带上插件名字作为前缀。
e. 如果插件中绑定了事件处理器,事件处理器最好放到一个事件命名空间,命名空间名字为插件的名字。
f. 如果插件使用data()为元素附件了数据,最好把所有数据放到一个对象里,名字为插件的名字,值为一个单一的对象。
g. 把插件代码用一个单独的文件保存,命名为jquery.plugin.js,其中plugin用你的插件名字代替。
一个插件也可以定义新的实用函数在jQuery对象上,如:jQuery.debug=function(){...}
除了定义新方法,我们可以对jQuery库的一些部分进行扩展。比如通过在jQuery.fx.speeds增加属性从而添加新的持续时间名称("fast","slow"),或者在jQuery.easing上增加属性来添加缓动函数。
插件甚至可以扩展jQuery的CSS选择器引擎,比如通过在jQuery.expr[':']对象上添加属性(其实是个选择器函数)来添加新的伪类过滤器(类似:first与:input),举个例子:
jQuery.expr[':'].draggable=function(e){return e.draggable===true;};
定了了上面的选择器,我们可以使用$("img:draggable")代替$("img[draggable=true]")来选择包含draggable属性的img元素<img draggable=true src="aa.icon"></img>
从上例看到,一个选择器函数有一个候选的DOM元素参数,如果元素匹配选择器,返回true,否则false。很多情况下只要一个DOM候选元素参数就行了,但是实际上这个函数调用是,传递了4个参数,第二个参数是当前元素在整个候选元素数组中的索引,候选元素数组是作为第四个参数传进来的,你不能修改这个参数。第三个参数很有趣,它是调用RegExp.exec()方法的结果数组,数组中的第四个元素是伪类过滤器后面圆括号中的值(如果存在的话)。例如实现这样一个伪类过滤器:data(x),它匹配包含属性data-x的元素:
jQuery.expr[':'].data=function(elem,index,match,array){return e.hasAttribute("data-"+match[3]);};