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>