观察者模式模拟YUI事件机制
首先介绍下YUI的事件机制,很好理解,因为和浏览器事件机制差不多。看懂下面几个方法就可以了:
publish: 创建自定义事件。第一个参数是事件类型,第二个参数是一个对象,里面可以设置默认动作
on: 监听事件, 在默认动作触发前执行回调。第一个参数是事件类型,第二个参数是回调函数
after: 监听事件,和 on 唯一不同的是在默认动作触发后执行回调
fire: 触发事件,类似于在浏览器里进行一次点击操作。第一个参数是事件类型,第二个参数是传递给回调函数的参数。
remove: 移除事件。第一个参数是事件类型,第二个参数是要移除的回调函数(如果为空,则移除该事件类型下所有的监听事件)
流程出来了,当一个自定义事件触发(fire)的时候,会进行如下处理:
什么是观察者模式?
维基百科的解释是:一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。
有点拗口,简单来讲就是有一个控制中心,这个控制中心管理着很多状态,如有个状态 x。而对象A(观察者)和对象B(观察者)对状态 x 很感兴趣,于是A和B在控制中心提交他们的兴趣,并告诉控制中心,当x发生变化时,及时通知他们。
根据 Javascript Patterns 这本书的介绍,浏览器中的事件机制用的就是观察者模式,所以,对于自定义事件,用观察者模式,是再适合不过了。
贴代码:
var EventCenter = {
events: [],
publish: function (type, def) {
var evt = this.events[type] = {};evt.def = typeof def === 'function' ? def : null;
evt.on = [];
evt.after = [];
},
fire: function (type, options) {
if(typeof this.events[type] === 'undefined') {
return false;
}
var evt = this.events[type],
i, len;//执行绑定在 on 上面的方法
for(i = 0, len = evt.on.length; i < len; i++) {
evt.on[i](options);
}
//执行默认方法
evt.def && evt.def(options);
//执行绑定在 after 上面的方法
for(i = 0, len = evt.after.length; i < len; i++) {
evt.after[i](options);
}
},
on: function (type, fn) {
if(typeof this.events[type] === 'undefined') {
return false;
}
this.events[type].on.push(fn);
},
after: function (type, fn) {
if(typeof this.events[type] === 'undefined') {
return false;
}
this.events[type].after.push(fn);
},
remove: function (type, fn) {
if(typeof this.events[type] === 'undefined') {
return false;
}
if(typeof fn !== 'function') {
delete this.events[type];
} else {
var evt = this.events[type],
i, len;for(i = 0, len = evt.on.length; i < len; i++) {
if(evt.on[i] === fn) {
evt.on.splice(i, 1);
}
}
for(i = 0, len = evt.after.length; i < len; i++) {
if(evt.after[i] === fn) {
evt.after.splice(i, 1);
}
}
}
}
};
简单测试下:
EventCenter.publish('abc', function (options) {
console.log('default ' + options.name);
});
EventCenter.on('abc', function (options) {
console.log('before default ' + options.name);
});EventCenter.after('abc', function (options) {
console.log('after default ' + options.name);
});EventCenter.fire('abc', {name: 'abc'});
结果如下:
这里面的publish方法的第二个参数直接就是一个默认回调,没有按照YUI的规范来写。这个例子主要是让大家对观察者模式和事件的处理机制有个大概的了解,明白里面是怎么个回事。当然,如果有兴趣,可以试着再往里加一些如阻止事件的默认行为和事件冒泡等功能。
延伸阅读:YUI事件模型:http://yuilibrary.com/yui/docs/event-custom/
观察者模式:《Javascript Patterns》第七章 Observer