浏览器Web的事件模型可分为两部分: 1. 监听事件的对象; 2. 分发的事件
1. 监听事件的对象: 基于 EventTarget 接口实现, 其负责事件的注册, 注销和派发
2. 分发的事件: 基于 Event 接口实现, 其负责创建出一个事件, 在需要派发事件的对象上广播该事件,广播可以被停止;
由此 , 便可构造出任意类型的事件, 在任意不同的对象上广播事件;
因为 Node,XMLHttpRequest 等对象都继承了 EventTarget 类, 所以可以在它们的实例上注册/注销/派发任意类型的事件
一个简易的 Event - EventTarget 事件模型实现
function MyEventTarget() { this.listeners = {} } MyEventTarget.prototype.addEventListener = function(type, callback, options) { if (this.listeners[type]) { this.listeners[type].push(callback) } else { this.listeners[type] = [callback] } } MyEventTarget.prototype.removeEventListener = function(type, callback) { var listeners, index; if (listeners = this.listeners[type]) { while (index = listeners.indexOf(callback) !== -1) { listeners.splice(index, 1) } } } MyEventTarget.prototype.dispatchEvent = function(event) { var type = event && event.type, listeners, callStack = event && event.path; if (callStack) { for(var i = 0; i < callStack.length; i++) { // 阻止了事件冒泡 if (!event.bubbles) { break; } if (type && (listeners = callStack[i].listeners[type])) { for (var k = 0; k < listeners.length; k++) { // 阻止了事件的继续派发 if (event.eventPhase === 0) { // 停止派发 } else { listeners[k].call(event.target, event) } } } } } else { if (type && (listeners = this.listeners[type])) { for (var k = 0; k < listeners.length; k++) { if (event.eventPhase === 0) { // 停止派发 } else { listeners[k].call(event.target, event) } } } } } var myEv1 = new MyEventTarget(); function fn1(e) { console.log('第一个 监听 1', e.data) } function fn2(e) { e.data += '555' console.log('第一个 监听 2', e.data); // e.stopPropagation(); // e.stopImmediatePropagation() } function fn3(e) { console.log('第一个 监听 3', e.data); } myEv1.addEventListener('show', fn1) myEv1.addEventListener('show', fn2); myEv1.addEventListener('show', fn3) var myEv2 = new MyEventTarget(); function pfn1(e) { console.log('第二个 监听 1', e.data); } myEv2.addEventListener('show', pfn1) function myEvent(type, data, path) { this.type = type this.eventPhase = 2 this.bubbles = true this.data = data this.path = path } myEvent.prototype.stopImmediatePropagation = function() { this.eventPhase = 0; } myEvent.prototype.stopPropagation = function() { this.bubbles = false } myEv1.dispatchEvent(new myEvent('show', '你好', [myEv1, myEv2]));