浏览器端的EventEmitter
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 8 <title>Document</title> 9 </head> 10 11 <body> 12 <script> 13 // 浏览器端的EventEmitter 14 /** 15 * 采用的发布订阅模式-和vue中的eventBus类似 16 * 将eventBus作为组件传递数据的桥梁,所有组件公用相同的事件中心,可以向该中心注册发送事件或接收事件, 17 * 所有组件都可以收到通知,使用起来非常便利,其核心就是发布-订阅模式的落地实现 18 */ 19 function EventEmitter(params) { 20 this.__events = {} 21 } 22 EventEmitter.VERSION = '1.0.0' 23 // 实现on方法 24 EventEmitter.prototype.on = function (eventName, listener) { 25 if (!eventName || !listener) return 26 if (!isValidListener(listener)) { 27 throw new TypeError('listener must be a function') 28 29 } 30 var events = this.__events 31 var listeners = events[eventName] = events[eventName] || [] 32 var listenerIsWrapped = typeof listener === 'object'; 33 // 不添加重复事件,判断是否有一样的 34 if (indexOf(listeners, listener) === -1) { 35 listeners.push(listenerIsWrapped ? listener : { 36 listener: listener, 37 once: false 38 }) 39 } 40 return this 41 } 42 // 判断 43 function isValidListener(listener) { 44 if (typeof listener === 'function') { 45 return true 46 } else if (listener && typeof listener === 'object') { 47 return isValidListener(listener.listener) 48 } else { 49 return false 50 } 51 52 } 53 // 判断新增自定义事件是否存在 54 function indexOf(array, item) { 55 var result = -1; 56 item = typeof item === "object" ? item.listener : item 57 for (let i = 0; i < array.length; i++) { 58 const element = array[i].listener; 59 if (element === item) { 60 result = i 61 break 62 } 63 64 } 65 return result 66 67 } 68 69 EventEmitter.prototype.emit = function (eventName, args) { 70 // 直接通过内部对象获取自定义事件的回调函数 71 var listener = this.__events[eventName] 72 if (!listeners) return 73 for (let i = 0; i < listeners.length; i++) { 74 const element = listeners[i]; 75 if (listener) { 76 listener.listener.apply(this, args || []) 77 // 给listener中的once为true的进行特殊处理 78 if (listener.once) { 79 this.off(eventName, listener.listener) 80 } 81 } 82 83 } 84 return this 85 } 86 EventEmitter.prototype.off = function (eventName, args) { 87 var listeners = this.__events[eventName] 88 if (!listeners) { 89 return 90 } 91 var index; 92 for (var i = 0, len = listeners.length; i < len; i++) { 93 if (listeners[i]&&listeners[i].listener===listener) { 94 index=i 95 break 96 } 97 98 } 99 if (typeof index!=='undefined') { 100 listeners.splice(index,1,null) 101 } 102 return this 103 } 104 EventEmitter.prototype.once = function (eventName, listener) { 105 // 直接调用on方法,once参数传入true,待执行之后进行once处理 106 return this.on(eventName,{ 107 listener:listener, 108 once 109 }) 110 } 111 EventEmitter.prototype.allOff = function (eventName) { 112 // 如果该eventName存在,则将其对应的listeners的数组直接清空 113 if (eventName&&this.__events[eventName]) { 114 this.__events[eventName]=[] 115 }else{ 116 this.__events={} 117 } 118 } 119 120 </script> 121 </body> 122 123 </html>