26-讨论
9.6.3 讨论
1.重载需要的方法
首先,创建一个函数,用自己的函数替代jQuery方法。将其命名为 jQuery.broadcast() ,如果你喜欢其他名称,可以修改:
(function($){
$.broadcast = function(name){
// 保存原始方法
var old = $.fn[name];
$.fn[name] = function(){
// 广播
};
};
})(jQuery);
name 必须是我们想要覆盖的方法名称,例如:
jQuery.broadcast('addClass');
2.在执行之前触发一个事件
既然我们将自己的方法当作jQuery方法,就让我们来看看如何触发一个事件,使我们能够修改输入的参数:
//创建一个事件对象
var e = $.Event('before-'+name);
// 将参数保存到对象中
e.args = $.makeArray(arguments);
//触发事件
this.trigger(e);
假定要广播 addClass() ,现在可以这么做:
jQuery('body').bind('before-addClass',function(e){
e.args[0]; // CSS类
});
3.执行原始方法
现在触发一个事件,但是仍然必须调用旧的 addClass() 。因为将把返回的数据保存在事件对象中,所以在触发其他事件的时候,仍然可以提供这些数据。
e.ret = old.apply(this, e.args);
正如你所看到的,不传递原始的 arguments 数组,而用自己提供的数据代替,以防它们以某种方式修改。
4.在执行之后触发事件
现在将返回的数据保存在事件对象中,可以触发最后一个事件,允许已返回数据的外部修改。
重用同一个事件对象,但是修改事件的名称。
e.type = 'after-'+name;
this.trigger(e);
5.返回结果
现在剩下的工作就是返回结果数据,继续正常的执行流程。将返回保存在 e.ret上 的数据,该数据可能已经被某个事件处理程序修改:
return e.ret;
6.全部整合到一起
下面是开发的完整代码:
(function($){
$.broadcast = function(name){
var old = $.fn[name];
$.fn[name] = function(){
var e = $.Event('before-'+name);
e.args = $.makeArray(arguments);
this.trigger(e);
e.ret = old.apply(this, e.args);
e.type = 'after-'+name;
this.trigger(e);
return e.ret;
};
};
})(jQuery);
7.还有哪些可以改进之处
我尽量保持示例简明扼要。对这个例子还有许多可以改进的地方,下面是几种思路:
- 使用
triggerHandler()代替trigger():如果不需要事件冒泡,可以简单地使用triggerHandler(),这个方法会使整个过程更快;注意,triggerHandler()只触发集合中第一个元素上的事件。 - 在每个元素上单独运行:在前面的例子中,
trigger()在整个集合上运行一次。对于大多数情况这是没有问题的,但是当用在有多个元素的集合上时可能得到出乎意料的结果。
可以调用 map() 包装在函数中放入的功能,这能使代码在每个元素上都运行一次。
这样做的缺点是速度可能稍慢,由于调用 map() ,还将生成一个(预期之外)的栈条目。
- 允许外部代码阻止正常地执行:如果使用的是jQuery 1.3或者更高版本,可以利用
jQuery.Event的方法。
可以用 e.isDefaultPrevented() “询问”事件对象是否有其他代码调用了它的 preventDefault() 方法。
如果 e.isDefaultPrevented() 返回 true ,就不要调用原始函数。
- 避免多次重载同一jQuery方法:这很简单;只要创建一个内部对象,记录重载的方法,然后只要忽略重复的调用就可以了。
- 与
jQuery.event.special集成:这样就不必为所要重载的每个方法调用jQuery.broadcast()了。
作为替代,为每个方法在 jQuery.event.special 中添加一个条目,当其他代码绑定事件的时候从内部调用 jQuery.broadcast() 。这应该与重复调用的检查组合使用。