22-讨论
9.5.3 讨论
1.一个示例
现在,将创建一个简单的幻灯片插件。我将在自己的一个现有插件 jQuery.SerialScroll [4]基础上建立这个插件。我在编写这个插件时第一次想到这种方法,老实说,它工作得不错。
将自己的插件命名为 slideshow 。它接收一个 <img> 元素和一个URL数组,然后循环显示这些图片。能够移动到上一张/下一张图片,跳转到某张图片,也可以自动循环显示。
从基础的功能开始:
(function( $ ){
$.fn.slideshow = function(options){
return this.each(function(){
var $img = $(this),
current = 0;
// 添加幻灯片演示行为...
});
};
})( jQuery );
现在,将添加几个局部函数,使我们能转移到集合中的不同图片(URL):
function show( index ){
var total = options.images.length;
while( index < 0 )
index += total;
while( index >= total )
index−= total;
current = index;
$img.attr('src', options.images[index]);
}
function prev(){
show( current−1 );
}
function next(){
show( current + 1 );
}
可以用事件提供这些功能:
$img.bind('prev', prev).bind('next', next).bind('goto',function(e, index){
show( index );
});
自动循环怎么做?再添加几个函数:
var auto = false, id;
function start(){
stop();
auto = true;
id = setTimeout(next, options.interval || 2000);
}
function stop(){
auto = false;
clearTimeout(id);
}
下面是事件:
$img.bind('start', start).bind('stop', stop);
现在需要在 show() 中添加几行,在必要时保持自动循环:
function show( index ){
//和以前一样…
if( auto )
start();
}
这就可以了!现在有了具备后退、前进和自动循环功能的完整幻灯片演示程序。
为了清晰地说明这个示例,我使这个插件完全依赖于外部操纵。
下面是一个具体实现的模型:
<ul>
<li><img id="prev" src="prev.png" /></li>
<li><img id="slideshow" /></li>
<li><img id="next" src="next.png" /></li>
</ul>
...
(function( $ ){
var $image = $('#slideshow');
$image.slideshow({
images: ['1.jpg', '2.jpg', '3.jpg', '4.jpg'],
interval: 3000
});
$('#prev').click(function(){
$image.trigger('prev');
});
$('#next').click(function(){
$image.trigger('next');
});
$image.trigger('goto', 0); // 初始化为0
$image.trigger('start'); // 我们打算自动循环显示
})( jQuery );
注意
这是使用
trigger()是因为它很简短,事实却是,如果使用triggerHandler()可能会更快,因为trigger()将产生事件冒泡(从jQuery 1.3起),而你可能并不需要这种功能。
2.如果元素已经有其中一个事件会发生什么?
可能发生一种情况(尽管这很奇怪): #slideshow 元素可能已经绑定了名为 prev 、 next 、 goto 、 start 或者 stop 的事件。
如果出现这种情况,解决方案见秘诀8.4。
3.如何允许其他代码清理添加的事件处理程序?
因为没有提供绑定的函数,所以其他外部代码无法解除它们的绑定。
在大部分情况下,可以简单地从事件中解除所有事件的绑定,例如:
jQuery('#slideshow').unbind('prev next goto start stop'); // 列举所有事件
//或者
jQuery('#slideshow').unbind(); //盲目地删除所有绑定
如果你需要谨慎地进行绑定解除,或者只是想要解除所有相关事件的绑定,查阅秘诀8.3。
4.与其他方法有何区别
现在还有其他的技术能够实现外部操纵。我将对其中一些进行比较:
允许插件接受命令 。jQuery UI(以及其他一些插件)使用这种模式。
这种模式就是当插件接受一个字符串作为第一个参数时执行操作,例如:
jQuery('#image').slideshow('goto', 1);
这种写法比使用事件的方法短一些,但是要求你用公开的方法保存所有必需的数据(在例子中是当前索引),以便后续的数据获取。利用这种模式的人也倾向于使用 date() 存储这些变量。
如果使用事件,可以简单地使用局部变量,因为事件处理程序可以访问插件的局部作用域。
返回带有方法的对象 。Jörn Zaefferer的 validate 插件(以及其他的一些插件)使用这种模式。
根据编码方式,对象的方法可能访问局部变量。为此必须使用闭包[5],而闭包是不能滥用的。而且,需要在某个地方(以全局方式)存储这个对象,还要求进行伪面向对象编码(你可能喜欢这种方式,也可能不喜欢)。
可以混合使用这两种方法以及前面介绍过的方法。可以创建一个对象(使用 jQuery.listener )并绑定事件然后返回对象,而不是将事件( prev 、 next 等)。绑定到DOM元素。正如我们在秘诀9.2中所看到的,这个监听器对象不仅限于事件。它可以拥有方法甚至在其属性中存储事件数据。