description interface IEvent { type : string ; target : any ; callback : ( ( data : any ) => void ) | string ; } export class EventDispatcher { private static _instance : EventDispatcher = null ; public static Instance ( ) { return this . _instance || ( this . _instance = new EventDispatcher ( ) ) ; } private logTag = `[EventDispatcher] ` ; private _eventCaches : { [ key ] : Array < IEvent > ; } = null ; constructor ( ) { this . _eventCaches = { } ; } description param type param callback param target public addEventListener ( type , callback , target ) { if ( ! type || ! callback || ! target ) return ; let eventCaches = this . _eventCaches [ type ] || [ ] ; let hasSame = false ; for ( let i = 0 ; i < eventCaches . length ; i ++ ) { if ( eventCaches [ i ] . target === target ) { hasSame = true ; break ; } } if ( hasSame ) { return ; } let newEvent = { type : type , callback : callback , target : target } ; eventCaches . push ( newEvent ) ; this . _eventCaches [ type ] = eventCaches ; } description param type param target public removeEventListener ( type , target ) { if ( ! type || ! target ) { return ; } let eventCaches = this . _eventCaches [ type ] ; if ( ! eventCaches ) { return ; } for ( let i = 0 ; i < eventCaches . length ; i ++ ) { if ( eventCaches [ i ] . target === target ) { eventCaches . splice ( i , 1 ) ; break ; } } if ( eventCaches . length == 0 ) { delete this . _eventCaches [ type ] ; } } description param type param data public dispatchEvent ( type , data ? ) { if ( ! type ) return ; let eventCaches = this . _eventCaches [ type ] ; if ( ! eventCaches ) return ; for ( let i = 0 ; i < eventCaches . length ; i ++ ) { let event = eventCaches [ i ] ; try { if ( typeof Reflect == "object" ) { if ( typeof event . callback == "string" ) { let func = Reflect . get ( event . target , event . callback ) ; if ( func ) { if ( CC_DEBUG ) cc . log ( `${ this . logTag } apply string func : ${ event . callback } class : ${ cc . js . getClassName ( event . target ) }` ) ; Reflect . apply ( func . bind ( event . target ) , event . target , [ data ] ) ; } else { if ( CC_DEBUG ) cc . error ( `${ this . logTag } class : ${ cc . js . getClassName ( event . target ) } no func : ${ event . callback }` ) ; } } else { Reflect . apply ( event . callback , event . target , [ data ] ) ; } } else { if ( typeof event . callback == "string" ) { if ( event . target && event . callback ) { let func = event . target [ event . callback ] ; if ( func && typeof func == "function" ) { func . apply ( event . target , [ data ] ) ; } else { if ( CC_DEBUG ) cc . error ( `${ event . callback } is not function` ) ; } } else { if ( CC_DEBUG ) cc . error ( `target or callback is null` ) ; } } else { if ( event . callback && event . target ) { event . callback . apply ( event . target , [ data ] ) ; } else { if ( CC_DEBUG ) cc . error ( `callback is null` ) ; } } } } catch ( error ) { cc . error ( error ) ; } } } } window . dispatch = function ( name , data ? ) { if ( CC_DEBUG && ! CC_EDITOR ) cc . log ( `[dispatch] ${ name } data : ${ data }` ) ; EventDispatcher . Instance ( ) . dispatchEvent ( name , data ) ; } ;