1 /** 2 * Hilo 3 * Copyright 2015 alibaba.com 4 * Licensed under the MIT License 5 */ 6 7 /** 8 * @language=zh 9 * @class EventMixin是一个包含事件相关功能的mixin。可以通过 Class.mix(target, EventMixin) 来为target增加事件功能。 10 * @mixin 11 * @static 12 * @module hilo/event/EventMixin 13 * @requires hilo/core/Class 14 */ 15 var EventMixin = { 16 _listeners: null, 17 18 /** 19 * @language=zh 20 * 增加一个事件监听。 21 * @param {String} type 要监听的事件类型。 22 * @param {Function} listener 事件监听回调函数。 23 * @param {Boolean} once 是否是一次性监听,即回调函数响应一次后即删除,不再响应。 24 * @returns {Object} 对象本身。链式调用支持。 25 */ 26 on: function(type, listener, once){ 27 var listeners = (this._listeners = this._listeners || {}); 28 var eventListeners = (listeners[type] = listeners[type] || []); 29 for(var i = 0, len = eventListeners.length; i < len; i++){ 30 var el = eventListeners[i]; 31 if(el.listener === listener) return; 32 } 33 eventListeners.push({listener:listener, once:once}); 34 return this; 35 }, 36 37 /** 38 * @language=zh 39 * 删除一个事件监听。如果不传入任何参数,则删除所有的事件监听;如果不传入第二个参数,则删除指定类型的所有事件监听。 40 * @param {String} type 要删除监听的事件类型。 41 * @param {Function} listener 要删除监听的回调函数。 42 * @returns {Object} 对象本身。链式调用支持。 43 */ 44 off: function(type, listener){ 45 //remove all event listeners 46 if(arguments.length == 0){ 47 this._listeners = null; 48 return this; 49 } 50 51 var eventListeners = this._listeners && this._listeners[type]; 52 if(eventListeners){ 53 //remove event listeners by specified type 54 if(arguments.length == 1){ 55 delete this._listeners[type]; 56 return this; 57 } 58 59 for(var i = 0, len = eventListeners.length; i < len; i++){ 60 var el = eventListeners[i]; 61 if(el.listener === listener){ 62 eventListeners.splice(i, 1); 63 if(eventListeners.length === 0) delete this._listeners[type]; 64 break; 65 } 66 } 67 } 68 return this; 69 }, 70 71 /** 72 * @language=zh 73 * 发送事件。当第一个参数类型为Object时,则把它作为一个整体事件对象。 74 * @param {String} type 要发送的事件类型。 75 * @param {Object} detail 要发送的事件的具体信息,即事件随带参数。 76 * @returns {Boolean} 是否成功调度事件。 77 */ 78 fire: function(type, detail){ 79 var event, eventType; 80 if(typeof type === 'string'){ 81 eventType = type; 82 }else{ 83 event = type; 84 eventType = type.type; 85 } 86 87 var listeners = this._listeners; 88 if(!listeners) return false; 89 90 var eventListeners = listeners[eventType]; 91 if(eventListeners){ 92 var eventListenersCopy = eventListeners.slice(0); 93 event = event || new EventObject(eventType, this, detail); 94 if(event._stopped) return false; 95 96 for(var i = 0; i < eventListenersCopy.length; i++){ 97 var el = eventListenersCopy[i]; 98 el.listener.call(this, event); 99 if(el.once) { 100 var index = eventListeners.indexOf(el); 101 if(index > -1){ 102 eventListeners.splice(index, 1); 103 } 104 } 105 } 106 107 if(eventListeners.length == 0) delete listeners[eventType]; 108 return true; 109 } 110 return false; 111 } 112 }; 113 114 /** 115 * @language=zh 116 * 事件对象类。当前仅为内部类,以后有需求的话可能会考虑独立为公开类。 117 */ 118 var EventObject = Class.create({ 119 constructor: function EventObject(type, target, detail){ 120 this.type = type; 121 this.target = target; 122 this.detail = detail; 123 this.timeStamp = +new Date(); 124 }, 125 126 type: null, 127 target: null, 128 detail: null, 129 timeStamp: 0, 130 131 stopImmediatePropagation: function(){ 132 this._stopped = true; 133 } 134 }); 135 136 //Trick: `stopImmediatePropagation` compatibility 137 var RawEvent = window.Event; 138 if(RawEvent){ 139 var proto = RawEvent.prototype, 140 stop = proto.stopImmediatePropagation; 141 proto.stopImmediatePropagation = function(){ 142 stop && stop.call(this); 143 this._stopped = true; 144 } 145 } 146