8.4 提供灵活的方法参数
在第7章中,我们看到了一些通过调整参数来使插件满足自己需求的例子。那些巧妙构思的插件通过定义恰当的默认值,并允许我们覆盖这些默认值提供了极大的灵活性。在轮到我们编写插件的时候,也应该替用户考虑到这一点。
为说明让插件用户定制插件行为的不同方式,我们来看一个例子,其中包含可以调整和修改的多项设置。这个例子是一个为元素块加投影的插件方法。同样的效果可以通过高级的CSS技术完成,但我们这里要使用一个更“暴力”的JavaScript方式:创建一些部分透明的元素,然后把它们相继排列在页面的不同位置上,参见代码清单8-11。
代码清单8-11
(function($) {
$.fn.shadow = function() {
return this.each(function() {
var $originalElement = $(this);
for (var i = 0; i < 5; i++) {
$originalElement
.clone()
.css({
position: 'absolute',
left: $originalElement.offset().left + i,
top: $originalElement.offset().top + i,
margin: 0,
zIndex: -1,
opacity: 0.1
})
.appendTo('body');
}
});
};
})(jQuery);
对于每个调用此方法的元素,都要复制该元素一定数量的副本,调整每个副本的不透明度。然后,再通过绝对定位方式,以该元素为基准按照不同的偏移量定位这些副本。现在,这个插件方法不接受任何参数,因此调用该方法很简单。
$(document).ready(function() {
$('h1').shadow();
});
调用结果就是在标题下方添加了阴影效果,如图8-5所示。
图 8-5
接下来,我们就赋予这个插件方法一些灵活性。这个方法的操作取决于一些用户可能想要修改值。可以把这些值提取出来作为参数,以便用户根据需要修改。
8.4.1 参数对象
在介绍jQuery API时,我们曾看到过很多将对象作为(.animate()
、$.ajax()
等)方法参数的例子。作为一种向插件用户公开选项的方式,对象要比刚刚使用的参数列表更加友好。对象会为每个参数提供一个有意义的标签,同时也会让参数次序变得无关紧要。而且,只要有可能通过插件来模仿jQuery API,就应该使用对象来提高一致性和易用性,参见代码清单8-12。
代码清单8-12
- (function($) {
- $.fn.shadow = function(options) {
- return this.each(function() {
- var $originalElement = $(this);
- for (var i = 0; i < options.copies; i++) {
- $originalElement
- .clone()
- .css({
- position: 'absolute',
- left: $originalElement.offset().left + i,
- top: $originalElement.offset().top + i,
- margin: 0,
- zIndex: -1,
- opacity: options.opacity
- })
- .appendTo('body');
- }
- });
- };
- })(jQuery);
这样,副本的数量和不透明度就可以自定义了。在这个插件中,可以通过函数参数options
的属性来访问每一个值。
再调用这个方法则需要传递一个包含选项值的对象,而不是独立的参数了:
$(document).ready(function() {
$('h1').shadow({
copies: 3,
opacity: 0.25
});
});
配置能力得到了改进,但每次都必须提供两个选项才行。下一节,我们就来解决这个问题,看看怎么让用户可以忽略任何一个选项。
8.4.2 默认参数值
随着方法的参数逐渐增多,始终指定每个参数并不是必须的。此时,一组合理的默认值可以增强插件接口的易用性。所幸的是,以对象作为参数可以帮我们很好地达成这一目标,它可以为用户未指定的参数自动传入默认值,参见代码清单8-13。
代码清单8-13
(function($) {
$.fn.shadow = function(opts) {
var defaults = {
copies: 5,
opacity: 0.1
};
var options = $.extend(defaults, opts);
// ...
};
})(jQuery);
在这个方法的定义中,我们定义了一个新对象,名为defaults
。实用函数$.extend()
可以用接受的opts
对象参数覆盖defaults
中的选项,并保持选项对象中未指定的默认项不变。
接下来,我们仍然以对象调用同一个方法,但这次只指定一个有别于默认值的不同参数:
$(document).ready(function() {
$('h1').shadow({
copies: 3
});
});
未指定的参数使用预先定义的默认值。$.extend()
方法甚至可以接受null
值,在用户可以接受所有默认参数时,我们的方法可以直接执行而不会出现JavaScript错误。
$(document).ready(function() {
$('h1').shadow();
});
8.4.3 回调函数
当然,方法参数也可能不是一个简单的数字值,可能会更复杂。在各种jQuery API中经常可以看到另一种参数类型,即回调函数。回调函数可以极大地增加插件的灵活性,但却用不着在创建插件时多编写多少代码。
要在方法中使用回调函数,需要接受一个函数对象作为参数,然后在方法中适当的位置上调用该函数。例如,可以扩展前面定义的文本投影方法,让用户能够自定义投影相对于文本的位置,参见代码清单8-14。
代码清单8-14
- (function($) {
- $.fn.shadow = function(opts) {
- var defaults = {
- copies: 5,
- opacity: 0.1,
- copyOffset: function(index) {
- return {x: index, y: index};
- }
- };
- var options = $.extend(defaults, opts);
- return this.each(function() {
- var $originalElement = $(this);
- for (var i = 0; i < options.copies; i++) {
- var offset = options.copyOffset(i);
- $originalElement
- .clone()
- .css({
- position: 'absolute',
- left: $originalElement.offset().left + offset.x,
- top: $originalElement.offset().top + offset.y,
- margin: 0,
- zIndex: -1,
- opacity: options.opacity
- })
- .appendTo('body');
- }
- });
- };
- })(jQuery);
投影的每个“切片”相对于原始文本都有不同的偏移量。此前,这个偏移量简单地等于切片的索引值。现在,偏移量都根据copyOffset()
函数来计算,而这个函数是用户可以覆盖的参数。例如,用户可以在两个方向上指定负值偏移量:
- $(document).ready(function() {
- $('h1').shadow({
- copyOffset: function(index) {
- return {x: -index, y: -2 * index};
- }
- });
- });
这样会导致投影叠加起来并向左上方(不是向右下方)延伸,如图8-6所示。
图 8-6
回调函数可以像这样简单地修改投影方向,也可以根据插件用户的定义,对投影位置作出更复杂的调整。如果未指定回调函数,则会使用默认行为。
8.4.4 可定制的默认值
我们在前面已经看到了,通过为方法参数设定合理的默认值,能够显著改善用户使用插件的体验。但是,到底什么默认值合理有时候也很难说。如果用户脚本会多次调用我们的插件,每次调用都要传递一组不同于默认值的参数,那么通过定制默认值就可以减少很多需要编写的代码量。
要支持默认值的可定制,需要把它们从方法定义中移出,然后放到外部代码可以访问的地方,如代码清单8-15所示。
代码清单8-15
(function($) {
$.fn.shadow = function(opts) {
var options = $.extend({}, $.fn.shadow.defaults, opts);
// ...
};
$.fn.shadow.defaults = {
copies: 5,
opacity: 0.1,
copyOffset: function(index) {
return {x: index, y: index};
}
};
})(jQuery);
默认值被放在了投影插件的命名空间里,可以通过$.fn.shadow.defaults
直接引用。而对$.extend()
的调用也必须修改,以适应这种变化。由于现在所有对.shadow()
的调用都要重用defaults
对象,因此不能让$.extend()
修改它。我们就在此将一个空对象({}
)作为$.extend()
的第一个参数,让这个新对象成为被修改的目标。
于是,使用我们插件的代码就可以修改默认值了,修改之后的值可以被所有后续对.shadow()
的调用共享。而且,在调用方法时仍然可以传递选项。
- $(document).ready(function() {
- $.fn.shadow.defaults.copies = 10;
- $('h1').shadow({
- copyOffset: function(index) {
- return {x: -index, y: index};
- }
- });
- });
因为在此提供了新的默认值,以上脚本会创建带10个切片的投影。由于在调用方法时提供了copyOffset
回调函数,所以投影也将朝向左下方,如图8-7所示。
图 8-7