8.3 添加 jQuery 对象方法
jQuery中大多数内置的功能都是通过其对象实例的方法提供的,而且这些方法也是插件之所以诱人的关键。当函数需要操作DOM元素时,就是将函数创建为jQuery
实例方法的好机会。
前面我们已经看到,添加全局函数需要以新方法来扩展jQuery
对象。添加实例方法也与此类似,但扩展的却是jQuery.fn
对象:
jQuery.fn.myMethod = function() {
alert('Nothing happens.');
};
jQuery.fn
对象是jQuery.prototype
的别名,使用别名是出于简洁的考虑。
然后,就可以在使用任何选择符表达式之后调用这个新方法了:
$('div').myMethod();
当调用这个方法时会弹出一个警告框(文档中的每个<div>
显示一次)。由于这里并没有在任何地方用到匹配的DOM节点,所以为此编写一个全局函数也是一样的。由此可见,一个合理的实例方法应该包含对它的上下文的操作。
8.3.1 对象方法的上下文
在任何插件方法内部,关键字this
引用的都是当前的jQuery对象。因而,可以在this
上面调用任何内置的jQuery方法,或者提取它包含的DOM节点并操作该节点。为了确定可以怎样利用对象的上下文,下面我们来编写一个小插件,用以操作匹配元素的类。
这个新方法接受两个类名,每次调用更换应用于每个元素的类。尽管jQuery UI有一个健壮的.switchClass()
方法,甚至该方法都支持以动画方式切换类,但为了演示需要,我们还是自己再来写一个吧,参见代码清单8-8。
代码清单8-8
//未完成的代码
(function($) {
$.fn.swapClass = function(class1, class2) {
if (this.hasClass(class1)) {
this.removeClass(class1).addClass(class2);
}
else if (this.hasClass(class2)) {
this.removeClass(class2).addClass(class1);
}
};
})(jQuery);
$(document).ready(function() {
$('table').click(function() {
$('tr').swapClass('one', 'two');
});
});
首先,测试每个匹配的元素是否已经应用了class1
,如果是,则将该类替换成class2
。然后,再测试class2
并在必要时替换成class1
。如果两个类都不存在,则什么也不做。
在使用这个插件的代码中,我们为表格绑定了click
处理程序,当单击表格时在每一个行上都调用.swapClass()
。我们的目的是想把表头行的类one
切换成two
,把合计行的类two
切换成one
。然而,预期的结果并没有发生,如图8-3所示。
图 8-3
结果是每一行都应用了two
类。为了纠正这个问题,需要基于多次选择的元素来正确地处理jQuery对象。
8.3.2 隐式迭代
读者大概还记得,jQuery的选择符表达式可能会匹配零、一或多个元素。因此,在设计插件时必须考虑到所有这些可能的情况。然而,我们在此调用的.hasClass()
只会检查匹配的第一个元素。换句话说,我们应该独立检查和操作每一个元素。
要在无论匹配多个元素的情况下都保证行为正确,最简单的方式就是始终在方法的上下文上调用.each()
方法;这样就会执行隐式迭代,而执行隐式迭代对于维护插件与内置方法的一致性是至关重要的。
在调用的.each()
方法内部,this
依次引用每个DOM元素,因此可以调整代码依次检测每个匹配的元素,并为它们应用相应的类,参见代码清单8-9。
代码清单8-9
- (function($) {
- $.fn.swapClass = function(class1, class2) {
- this.each(function() {
- var $element = $(this);
- if ($element.hasClass(class1)) {
- $element.removeClass(class1).addClass(class2);
- }
- else if ($element.hasClass(class2)) {
- $element.removeClass(class2).addClass(class1);
- }
- });
- };
- })(jQuery);
this
的含义意!
在对象方法体内,关键字this
引用的是一个jQuery对象,但在每次调用的.each()
方法中,this
引用的则是一个DOM元素。
这样,再单击表格,切换类的操作就不会影响到不带有任何类的行了,如图8-4所示。
图 8-4
8.3.3 方法连缀
除了隐式迭代之外,jQuery用户也应该能够正常使用连缀行为。因而,我们必须在所有插件方法中返回一个jQuery对象,除非相应的方法明显用于取得不同的信息。返回的jQuery对象通常就是this
所引用的对象。如果我们使用.each()
迭代遍历this
,那么可以只返回迭代的结果,参见代码清单8-10。
代码清单8-10
- (function($) {
- $.fn.swapClass = function(class1, class2) {
- return this.each(function() {
- var $element = $(this);
- if ($element.hasClass(class1)) {
- $element.removeClass(class1).addClass(class2);
- }
- else if ($element.hasClass(class2)) {
- $element.removeClass(class2).addClass(class1);
- }
- });
- };
- })(jQuery);
前面在调用了.swapClass()
之后,如果想对元素再执行其他操作,必须通过一条新语句重新取得元素。而在添加return
之后,就可以在我们的插件方法上面连缀内置的方法了。