第一种方式:使用JavaScript原生提供的CustomEvent
创建自定义事件
比如可以这样创建:
var evt = new CustomEvent(type, {detail: msg, bubbles: true, cancelable: true});
然后监听并触发某个自定义事件
element.addEventListener('longpress', longpressFn);
element.dispatchEvent(evt);
第二种方式:自己模拟一个自定义事件发布订阅对象
var Event = (function() {
var clientList = {};
var listen,
trigger,
remove;
listen = function(key, fn) {
if (!clientList[key]) {
clientList[key] = [];
}
clientList[key].push(fn);
};
trigger = function() {
var key = [].shift.call(arguments);
var fns = clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (var i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments);
}
};
remove = function(key, fn) {
var fns = clientList[key];
// key对应的消息没有被人订阅
if (!fns) {
return false;
}
// 没有传入fn(具体的回调函数), 表示取消key对应的所有订阅
if (!fn) {
fns && (fns.length = 0);
}
else {
// 反向遍历
for (var i = fns.length - 1,_fn=fns[i]; i >= 0; i--) {
if (_fn === fn) {
// 删除订阅回调函数
fns.splice(i, 1);
}
}
}
};
return {
listen: listen,
trigger: trigger,
remove: remove
}
}());
这两种方式都能实现一个自定义事件的创建、监听、触发、删除,但区别是第一种是原生DOM提供的API,第二种是用发布订阅模式去模拟的?原生DOM的创建方式也是一种发布订阅模式么?
那在实际项目中用哪种比较好?查了下资料,发现用原生DOM的API貌似有IE方面的兼容问题
现在一些大型的库或者框架都是用第二种那样自己实现的自定义事件订阅系统么?(主要最近在造自己的轮子,听说这种模式可以降低代码的耦合度,想学习下。。)
你的订阅发布确定没问题么?我理解的,订阅发布结合面相对象来说,最简单的模式应该是至少有三部分:
发布消息者,消息本身,和订阅者。
原生dom的事件模式中,其实本身也就是一个订阅发布模式。
1.每个htmlElement类最基础的interface,都是eventTarget,也就是"发布消息者"。这个你可以看mdn:这里。
也就是说,HTMLElement有个继承链,Element---Node---EventTarget。EvetntTarget接口实现了发送消息的方法,所以,原生dom元素可以发送消息,也就是说,dom元素可以作为"发布消息者"。
2.每次事件发送的消息本身,其实按照面相对象来说,每次事件就是一个Event类的实例,每次有事件触发,都会创建一个消息Event实例,由发布消息者,也就是指定的dom元素,广播给订阅者。
3.dom模型中的订阅者,其实可以简单理解成就是我们注册好的"事件处理函数"。然而,实际上,按照dom标准,dom事件订阅者也是有个interface格式的:这里。满足了这个格式,就可以给eventTarget添加listener。每次有Event发出,不管你是自定义事件还是真的用户交互事件,都会触发listener。
你自己实现的那个,并没有抽象出这三个部分吧。当然,订阅发布完全可以自己订阅自己,消息也只在内部不暴露。只是感觉这样就很模糊了。
其实,你自己实现的订阅发布,每个接口原生JS的HTMLElement上都有了。只看最新的,你自己实现的那个listen方法,就是addEventListener;trigger方法,就是dispatchEvent;remove就是removeEventListener。而且你自己实现的那个并没有抽象出Event消息和订阅者。