DOM无关事件(节选自基于MVC的js富客户端应用)


  基于事件的编程非常强大,因为它能让你的应用架构充分解耦,让功能变得更加内聚且
具有更好的可维护性。事件本质上是和DOM无关的,因此你可以很容易开发出一个事
件驱动的库。这种模式称为发布/订阅(http://en.wikipedia.org/wiki/Publish/subscribe),
这是一个很有用的模式。
  发布/订阅(Pub/Sub)是一种消息模式,它有两个参与者:发布者和订阅者。发布者向
某个信道(channel)发布一条消息,订阅者绑定这个信道,当有消息发布至信道时就会
接收到一个通知。最重要的一点是,发布者和订阅者是完全解耦的,彼此并不知晓对方
的存在。两者仅仅共享一个信道名称。
  发布者和订阅者的解耦可以让你的应用易于扩展,而不必引入额外的交叉依赖和耦合,
从而提高了应用的可维护性,添加额外功能也非常容易。
那么,应当如何在应用中使用发布/订阅(Pub/Sub)模式呢?你只需记录回调和事件名
称的对应关系及调用它们的方法。看一下这个例子,这段代码中实现了PubSub对象,用
它可以添加并触发事件监听:

var PubSub = {
subscribe: function(ev, callback) {
// 创建 _callbacks 对象,除非它已经存在了
var calls = this._callbacks || (this._callbacks = {});
2831
// 针对给定的事件key创建一个数组,除非这个数组已经存在
// 然后将回调函数追加到这个数组中
(this._callbacks[ev] || (this._callbacks[ev] = [])).push(callback);
return this;
},
publish: function() {
// 将arguments对象转换为真正的数组
var args = Array.prototype.slice.call(arguments, 0);
// 拿出第1个参数,即事件名称
var ev = args.shift();
// 如果不存在_callbacks对象,则返回
// 或者如果不包含给定事件对应的数组
var list, calls, i, l;
if (!(calls = this._callbacks)) return this;
if (!(list = this._callbacks[ev])) return this;
// 触发回调
for (i = 0, l = list.length; i < l; i++)
list[i].apply(this, args);
return this;
}
};
// 使用方法
PubSub.subscribe("wem", function(){
alert("Wem!");
});
PubSub.publish("wem");

  你可以使用命名空间的方式来管理事件名称,比如使用冒号分隔符(:)。


  PubSub.subscribe("user:create", function(){ /* ... */ });


  如果你在使用jQuery,可以关注下Ben Alman(http://benalman.com)写的一个更容易
的库(http://gist.github.com/799721/c119783954e1b10551c4afef53b2c04fefcb7465)。这个
库非常简单,用不了一页纸:

/*!
* jQuery Tiny Pub/Sub - v0.3 - 11/4/2010
* http://benalman.com/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/

(function($){
var o = $({});
$.subscribe = function() {
o.bind.apply( o, arguments );
};
$.unsubscribe = function() {
o.unbind.apply( o, arguments );
};
$.publish = function() {
o.trigger.apply( o, arguments );
};
})(jQuery);

  这里的API和jQuery的bind()及trigger()函数的参数一致。惟一的区别就是这两个
函数直接保存在jQuery对象中,且名叫publish()和subscribe():


  $.subscribe( "/some/topic", function( event, a, b, c ) {
    console.log( event.type, a + b + c );
  });
  $.publish( "/some/topic", "a", "b", "c" );


  上面我们将Pub/Sub用于全局事件,也能很容易地将其用于局部事件。现在我们用上面
提到的PubSub对象来创建一个对象的局部事件:


var Asset = {};
// 添加PubSub
jQuery.extend(Asset, PubSub);
// 现在就可以用publish/subscribe函数了
Asset.subscribe("create", function(){
// ...
});


我们使用了jQuery的extend()来将PubSub的属性复制至Asset对象。这样的话,所有
对publish()和subscribe()的调用均是针对Asset的局部调用。这在很多场景中非常
有用,包括对象关系映射(ORM)中的事件、状态机及当Ajax请求结束时的回调等场景

posted @ 2015-04-19 22:58  风之约  阅读(152)  评论(0)    收藏  举报