├── README.md ├── index.js ├── lib └── eventemitter2.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # react-native-eventemitter 2 | 3 | [EventEmitter2](https://github.com/hij1nx/EventEmitter2) 在 React-Native 封装使用。 4 | 5 | ``` 6 | npm install react-native-eventemitter --save 7 | ``` 8 | 9 | ``` 10 | import EventEmitter from "react-native-eventemitter"; 11 | ``` 12 | 13 | 14 | 一个栗子 15 | ``` 16 | .... 17 | import EventEmitter from "react-native-eventemitter"; 18 | .... 19 | 20 | componentWillMount() { 21 | 22 | 23 | let callback = (v)=>{ 24 | console.log("Main:", v); 25 | }; 26 | //监听1 27 | EventEmitter.on("foo", (value)=>{ 28 | console.log("foo", value); 29 | }); 30 | //监听2 31 | EventEmitter.on("foo", callback); 32 | 33 | //监听匹配 34 | EventEmitter.on("foo.*", (value)=>{ 35 | console.log("ALL", value); 36 | }); 37 | //条件监听 事件执行2次后销毁 38 | EventEmitter.many('foo.*', 2, function(value) { 39 | console.log('foo', value); 40 | }); 41 | //移除所有监听 42 | //EventEmitter.removeAllListeners("foo"); 43 | //移除监听2 44 | //EventEmitter.removeListener("foo", callback); 45 | 46 | //触发事件1 47 | EventEmitter.emit("foo", "value"); 48 | //触发事件2 49 | EventEmitter.emit("foo.a", "value"); 50 | } 51 | 52 | .... 53 | 54 | 55 | 注: 56 | 57 | EventEmitter 为全局变量所以在其他组件中同样可以使用以上方式增加监听,或移除 58 | 59 | 建议在组件componentWillUnmount 时移除当前监听 60 | 61 | 栗子: 62 | ..... 63 | componentWillMount() { 64 | EventEmitter.on("foo", this.callback); 65 | } 66 | 67 | componentWillUnmount() { 68 | EventEmitter.removeListener("foo", this.callback); 69 | } 70 | 71 | callback(value) { 72 | console.log("foo", value); 73 | } 74 | ..... 75 | 76 | ``` 77 | 78 | 更多姿势参考 [EventEmitter2](https://github.com/hij1nx/EventEmitter2)。 79 | 80 | 81 | ## License 82 | 83 | (The MIT License) 84 | 85 | Copyright (c) 2016-2018 NetEase, Inc. and other contributors 86 | 87 | Permission is hereby granted, free of charge, to any person obtaining 88 | a copy of this software and associated documentation files (the 89 | 'Software'), to deal in the Software without restriction, including 90 | without limitation the rights to use, copy, modify, merge, publish, 91 | distribute, sublicense, and/or sell copies of the Software, and to 92 | permit persons to whom the Software is furnished to do so, subject to 93 | the following conditions: 94 | 95 | The above copyright notice and this permission notice shall be 96 | included in all copies or substantial portions of the Software. 97 | 98 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 99 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 100 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 101 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 102 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 103 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 104 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 105 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * Created by 陈桥 on 2016/7/13. 4 | * QQ:626164558 5 | * Email :chen.qiao@foxmail.com 6 | */ 7 | 8 | import EventEmitter from './lib/eventemitter2'; 9 | 10 | export default EventEmitter; 11 | -------------------------------------------------------------------------------- /lib/eventemitter2.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * EventEmitter2 3 | * https://github.com/hij1nx/EventEmitter2 4 | * 5 | * Copyright (c) 2013 hij1nx 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | var isArray = Array.isArray ? Array.isArray : function _isArray(obj) { 10 | return Object.prototype.toString.call(obj) === "[object Array]"; 11 | }; 12 | var defaultMaxListeners = 10; 13 | 14 | function init() { 15 | this._events = {}; 16 | if (this._conf) { 17 | configure.call(this, this._conf); 18 | } 19 | } 20 | 21 | function configure(conf) { 22 | if (conf) { 23 | 24 | this._conf = conf; 25 | 26 | conf.delimiter && (this.delimiter = conf.delimiter); 27 | conf.maxListeners && (this._events.maxListeners = conf.maxListeners); 28 | conf.wildcard && (this.wildcard = conf.wildcard); 29 | conf.newListener && (this.newListener = conf.newListener); 30 | 31 | if (this.wildcard) { 32 | this.listenerTree = {}; 33 | } 34 | } 35 | } 36 | 37 | function EventEmitter(conf) { 38 | this._events = {}; 39 | this.newListener = false; 40 | configure.call(this, conf); 41 | } 42 | 43 | // 44 | // Attention, function return type now is array, always ! 45 | // It has zero elements if no any matches found and one or more 46 | // elements (leafs) if there are matches 47 | // 48 | function searchListenerTree(handlers, type, tree, i) { 49 | if (!tree) { 50 | return []; 51 | } 52 | var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached, 53 | typeLength = type.length, currentType = type[i], nextType = type[i+1]; 54 | if (i === typeLength && tree._listeners) { 55 | // 56 | // If at the end of the event(s) list and the tree has listeners 57 | // invoke those listeners. 58 | // 59 | if (typeof tree._listeners === 'function') { 60 | handlers && handlers.push(tree._listeners); 61 | return [tree]; 62 | } else { 63 | for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) { 64 | handlers && handlers.push(tree._listeners[leaf]); 65 | } 66 | return [tree]; 67 | } 68 | } 69 | 70 | if ((currentType === '*' || currentType === '**') || tree[currentType]) { 71 | // 72 | // If the event emitted is '*' at this part 73 | // or there is a concrete match at this patch 74 | // 75 | if (currentType === '*') { 76 | for (branch in tree) { 77 | if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { 78 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1)); 79 | } 80 | } 81 | return listeners; 82 | } else if(currentType === '**') { 83 | endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*')); 84 | if(endReached && tree._listeners) { 85 | // The next element has a _listeners, add it to the handlers. 86 | listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength)); 87 | } 88 | 89 | for (branch in tree) { 90 | if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { 91 | if(branch === '*' || branch === '**') { 92 | if(tree[branch]._listeners && !endReached) { 93 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength)); 94 | } 95 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); 96 | } else if(branch === nextType) { 97 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2)); 98 | } else { 99 | // No match on this one, shift into the tree but not in the type array. 100 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); 101 | } 102 | } 103 | } 104 | return listeners; 105 | } 106 | 107 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1)); 108 | } 109 | 110 | xTree = tree['*']; 111 | if (xTree) { 112 | // 113 | // If the listener tree will allow any match for this part, 114 | // then recursively explore all branches of the tree 115 | // 116 | searchListenerTree(handlers, type, xTree, i+1); 117 | } 118 | 119 | xxTree = tree['**']; 120 | if(xxTree) { 121 | if(i < typeLength) { 122 | if(xxTree._listeners) { 123 | // If we have a listener on a '**', it will catch all, so add its handler. 124 | searchListenerTree(handlers, type, xxTree, typeLength); 125 | } 126 | 127 | // Build arrays of matching next branches and others. 128 | for(branch in xxTree) { 129 | if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) { 130 | if(branch === nextType) { 131 | // We know the next element will match, so jump twice. 132 | searchListenerTree(handlers, type, xxTree[branch], i+2); 133 | } else if(branch === currentType) { 134 | // Current node matches, move into the tree. 135 | searchListenerTree(handlers, type, xxTree[branch], i+1); 136 | } else { 137 | isolatedBranch = {}; 138 | isolatedBranch[branch] = xxTree[branch]; 139 | searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1); 140 | } 141 | } 142 | } 143 | } else if(xxTree._listeners) { 144 | // We have reached the end and still on a '**' 145 | searchListenerTree(handlers, type, xxTree, typeLength); 146 | } else if(xxTree['*'] && xxTree['*']._listeners) { 147 | searchListenerTree(handlers, type, xxTree['*'], typeLength); 148 | } 149 | } 150 | 151 | return listeners; 152 | } 153 | 154 | function growListenerTree(type, listener) { 155 | 156 | type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); 157 | 158 | // 159 | // Looks for two consecutive '**', if so, don't add the event at all. 160 | // 161 | for(var i = 0, len = type.length; i+1 < len; i++) { 162 | if(type[i] === '**' && type[i+1] === '**') { 163 | return; 164 | } 165 | } 166 | 167 | var tree = this.listenerTree; 168 | var name = type.shift(); 169 | 170 | while (name) { 171 | 172 | if (!tree[name]) { 173 | tree[name] = {}; 174 | } 175 | 176 | tree = tree[name]; 177 | 178 | if (type.length === 0) { 179 | 180 | if (!tree._listeners) { 181 | tree._listeners = listener; 182 | } 183 | else if(typeof tree._listeners === 'function') { 184 | tree._listeners = [tree._listeners, listener]; 185 | } 186 | else if (isArray(tree._listeners)) { 187 | 188 | tree._listeners.push(listener); 189 | 190 | if (!tree._listeners.warned) { 191 | 192 | var m = defaultMaxListeners; 193 | 194 | if (typeof this._events.maxListeners !== 'undefined') { 195 | m = this._events.maxListeners; 196 | } 197 | 198 | if (m > 0 && tree._listeners.length > m) { 199 | 200 | tree._listeners.warned = true; 201 | console.error('(node) warning: possible EventEmitter memory ' + 202 | 'leak detected. %d listeners added. ' + 203 | 'Use emitter.setMaxListeners() to increase limit.', 204 | tree._listeners.length); 205 | console.trace(); 206 | } 207 | } 208 | } 209 | return true; 210 | } 211 | name = type.shift(); 212 | } 213 | return true; 214 | } 215 | 216 | // By default EventEmitters will print a warning if more than 217 | // 10 listeners are added to it. This is a useful default which 218 | // helps finding memory leaks. 219 | // 220 | // Obviously not all Emitters should be limited to 10. This function allows 221 | // that to be increased. Set to zero for unlimited. 222 | 223 | EventEmitter.prototype.delimiter = '.'; 224 | 225 | EventEmitter.prototype.setMaxListeners = function(n) { 226 | this._events || init.call(this); 227 | this._events.maxListeners = n; 228 | if (!this._conf) this._conf = {}; 229 | this._conf.maxListeners = n; 230 | }; 231 | 232 | EventEmitter.prototype.event = ''; 233 | 234 | EventEmitter.prototype.once = function(event, fn) { 235 | this.many(event, 1, fn); 236 | return this; 237 | }; 238 | 239 | EventEmitter.prototype.many = function(event, ttl, fn) { 240 | var self = this; 241 | 242 | if (typeof fn !== 'function') { 243 | throw new Error('many only accepts instances of Function'); 244 | } 245 | 246 | function listener() { 247 | if (--ttl === 0) { 248 | self.off(event, listener); 249 | } 250 | fn.apply(this, arguments); 251 | } 252 | 253 | listener._origin = fn; 254 | 255 | this.on(event, listener); 256 | 257 | return self; 258 | }; 259 | 260 | EventEmitter.prototype.emit = function() { 261 | 262 | this._events || init.call(this); 263 | 264 | var type = arguments[0]; 265 | 266 | if (type === 'newListener' && !this.newListener) { 267 | if (!this._events.newListener) { return false; } 268 | } 269 | 270 | // Loop through the *_all* functions and invoke them. 271 | if (this._all) { 272 | var l = arguments.length; 273 | var args = new Array(l - 1); 274 | for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; 275 | for (i = 0, l = this._all.length; i < l; i++) { 276 | this.event = type; 277 | this._all[i].apply(this, args); 278 | } 279 | } 280 | 281 | // If there is no 'error' event listener then throw. 282 | if (type === 'error') { 283 | 284 | if (!this._all && 285 | !this._events.error && 286 | !(this.wildcard && this.listenerTree.error)) { 287 | 288 | if (arguments[1] instanceof Error) { 289 | throw arguments[1]; // Unhandled 'error' event 290 | } else { 291 | throw new Error("Uncaught, unspecified 'error' event."); 292 | } 293 | return false; 294 | } 295 | } 296 | 297 | var handler; 298 | 299 | if(this.wildcard) { 300 | handler = []; 301 | var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); 302 | searchListenerTree.call(this, handler, ns, this.listenerTree, 0); 303 | } 304 | else { 305 | handler = this._events[type]; 306 | } 307 | 308 | if (typeof handler === 'function') { 309 | this.event = type; 310 | if (arguments.length === 1) { 311 | handler.call(this); 312 | } 313 | else if (arguments.length > 1) 314 | switch (arguments.length) { 315 | case 2: 316 | handler.call(this, arguments[1]); 317 | break; 318 | case 3: 319 | handler.call(this, arguments[1], arguments[2]); 320 | break; 321 | // slower 322 | default: 323 | var l = arguments.length; 324 | var args = new Array(l - 1); 325 | for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; 326 | handler.apply(this, args); 327 | } 328 | return true; 329 | } 330 | else if (handler) { 331 | var l = arguments.length; 332 | var args = new Array(l - 1); 333 | for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; 334 | 335 | var listeners = handler.slice(); 336 | for (var i = 0, l = listeners.length; i < l; i++) { 337 | this.event = type; 338 | listeners[i].apply(this, args); 339 | } 340 | return (listeners.length > 0) || !!this._all; 341 | } 342 | else { 343 | return !!this._all; 344 | } 345 | 346 | }; 347 | 348 | EventEmitter.prototype.on = function(type, listener) { 349 | 350 | if (typeof type === 'function') { 351 | this.onAny(type); 352 | return this; 353 | } 354 | 355 | if (typeof listener !== 'function') { 356 | throw new Error('on only accepts instances of Function'); 357 | } 358 | this._events || init.call(this); 359 | 360 | // To avoid recursion in the case that type == "newListeners"! Before 361 | // adding it to the listeners, first emit "newListeners". 362 | this.emit('newListener', type, listener); 363 | 364 | if(this.wildcard) { 365 | growListenerTree.call(this, type, listener); 366 | return this; 367 | } 368 | 369 | if (!this._events[type]) { 370 | // Optimize the case of one listener. Don't need the extra array object. 371 | this._events[type] = listener; 372 | } 373 | else if(typeof this._events[type] === 'function') { 374 | // Adding the second element, need to change to array. 375 | this._events[type] = [this._events[type], listener]; 376 | } 377 | else if (isArray(this._events[type])) { 378 | // If we've already got an array, just append. 379 | this._events[type].push(listener); 380 | 381 | // Check for listener leak 382 | if (!this._events[type].warned) { 383 | 384 | var m = defaultMaxListeners; 385 | 386 | if (typeof this._events.maxListeners !== 'undefined') { 387 | m = this._events.maxListeners; 388 | } 389 | 390 | if (m > 0 && this._events[type].length > m) { 391 | 392 | this._events[type].warned = true; 393 | console.error('(node) warning: possible EventEmitter memory ' + 394 | 'leak detected. %d listeners added. ' + 395 | 'Use emitter.setMaxListeners() to increase limit.', 396 | this._events[type].length); 397 | console.trace(); 398 | } 399 | } 400 | } 401 | return this; 402 | }; 403 | 404 | EventEmitter.prototype.onAny = function(fn) { 405 | 406 | if (typeof fn !== 'function') { 407 | throw new Error('onAny only accepts instances of Function'); 408 | } 409 | 410 | if(!this._all) { 411 | this._all = []; 412 | } 413 | 414 | // Add the function to the event listener collection. 415 | this._all.push(fn); 416 | return this; 417 | }; 418 | 419 | EventEmitter.prototype.addListener = EventEmitter.prototype.on; 420 | 421 | EventEmitter.prototype.off = function(type, listener) { 422 | if (typeof listener !== 'function') { 423 | throw new Error('removeListener only takes instances of Function'); 424 | } 425 | 426 | var handlers,leafs=[]; 427 | 428 | if(this.wildcard) { 429 | var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); 430 | leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); 431 | } 432 | else { 433 | // does not use listeners(), so no side effect of creating _events[type] 434 | if (!this._events[type]) return this; 435 | handlers = this._events[type]; 436 | leafs.push({_listeners:handlers}); 437 | } 438 | 439 | for (var iLeaf=0; iLeaf 0) { 494 | fns = this._all; 495 | for(i = 0, l = fns.length; i < l; i++) { 496 | if(fn === fns[i]) { 497 | fns.splice(i, 1); 498 | return this; 499 | } 500 | } 501 | } else { 502 | this._all = []; 503 | } 504 | return this; 505 | }; 506 | 507 | EventEmitter.prototype.removeListener = EventEmitter.prototype.off; 508 | 509 | EventEmitter.prototype.removeAllListeners = function(type) { 510 | if (arguments.length === 0) { 511 | !this._events || init.call(this); 512 | return this; 513 | } 514 | 515 | if(this.wildcard) { 516 | var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); 517 | var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); 518 | 519 | for (var iLeaf=0; iLeaf