/** * @module event * @author [email protected] */ KISSY.add('event', function(S, undef) { var doc = document, DOM = S.DOM, simpleAdd = doc.addEventListener ? function(el, type, fn, capture) { if (el.addEventListener) { el.addEventListener(type, fn, !!capture); } } : function(el, type, fn) { if (el.attachEvent) { el.attachEvent('on' + type, fn); } }, simpleRemove = doc.removeEventListener ? function(el, type, fn, capture) { if (el.removeEventListener) { el.removeEventListener(type, fn, !!capture); } } : function(el, type, fn) { if (el.detachEvent) { el.detachEvent('on' + type, fn); } }, //红色部分的是原生的事件加载 EVENT_GUID = 'ksEventTargetId',//标识符 SPACE = ' ', guid = S.now(),//时间戳 // { id: { target: el, events: { type: { handle: obj, listeners: [...] } } }, ... } cache = { };//缓存 var Event = {//定义一个Event对象 EVENT_GUID: EVENT_GUID, // such as: { 'mouseenter' : { fix: 'mouseover', handle: fn } } special: { }, /** * Adds an event listener. * @param target {Element} An element or custom EventTarget to assign the listener to. * @param type {String} The type of event to append. * @param fn {Function} The event handler. * @param scope {Object} (optional) The scope (this reference) in which the handler function is executed. */ add: function(target, type, fn, scope /* optional */) {//添加一个事件 if (batch('add', target, type, fn, scope)) return;//如果需要batch做一下批量,通过batch的逻辑 // Event.add([dom,dom]) //getID var id = getID(target), isNativeEventTarget, special, events, eventHandle, fixedType, capture; // 不是有效的 target 或 参数不对 if (id === -1 || !type || !S.isFunction(fn)) return; // 还没有添加过任何事件 if (!id) {//如果目前的对象没有添加过id setID(target, (id = guid++));//set一个Id,并在cache里面存一个对应的对象,保存这个target和它对应的事件。 cache[id] = { target: target, events: { } }; } // 没有添加过该类型事件 events = cache[id].events;//events用来保存这个cache的events,用events来存储一个对象对应的event对象们 if (!events[type]) { isNativeEventTarget = !target.isCustomEventTarget; special = ((isNativeEventTarget || target._supportSpecialEvent) && Event.special[type]) || { }; eventHandle = function(event, eventData) {//eventHandle函数的定义,eventHandle是对事件添加的一层封装,原生的事件函数,只会有event这一个参数 if (!event || !event.fixed) { event = new S.EventObject(target, event, type);//新new一个EventObject } if (S.isPlainObject(eventData)) {//把eventData mix到event对象上面,这里都没有区分是不是元素的事件。 //protect type var typeo = event.type; S.mix(event, eventData); event.type = typeo; } if (special['setup']) {//如果是原生的事件或者是特殊的自定义事件,并定义了special方法,就通过special的setup方法来执行这个 special['setup'](event); } return (special.handle || Event._handle)(target, event);//返回值看special里面是否定义了handle,如果没有,就调用Event的_handle来处理target和event,默认的自定义事件的fire会来调用Event._handle方法, }; events[type] = {//在events对象下面的类型下面建立对应的type的对象 handle: eventHandle,//每一个类型的事件的eventHandle都会保存在此一份,只不过原生的js会再用simpleAdd再做一层原生的调用 listeners: [] }; fixedType = special.fix || type;//fix capture capture = special['capture']; if (special['init']) { special['init'].apply(null, S.makeArray(arguments)); } if (isNativeEventTarget && special.fix !== false) {//如果是原生的事件并且fix不是false,那么就用原生的添加事件。 simpleAdd(target, fixedType, eventHandle, capture); } } // 增加 listener events[type].listeners.push({fn: fn, scope: scope || target});//对events对应的类型的listener下面push进对应的fn和eventHandle。 }, __getListeners:function(target, type) {//获取一个event对象的Listeners var events = Event.__getEvents(target) || {}, eventsType, listeners = []; if ((eventsType = events[type])) { listeners = eventsType.listeners; } return listeners; }, __getEvents:function(target) {//获取一个对象上面的事件 var id = getID(target),c, events; if (id === -1) return; // 不是有效的 target if (!id || !(c = cache[id])) return; // 无 cache if (c.target !== target) return; // target 不匹配 events = c.events || { }; return events; }, /** * Detach an event or set of events from an element. */ remove: function(target, type /* optional */, fn /* optional */, scope /* optional */) { if (batch('remove', target, type, fn, scope)) return; var events = Event.__getEvents(target), id = getID(target), eventsType, listeners, len, i, j, t, isNativeEventTarget = !target.isCustomEventTarget,//isCustomEventTarget是外部传入的一个配置属性 special = ((isNativeEventTarget || target._supportSpecialEvent) && Event.special[type]) || { }; if (events === undefined) return; scope = scope || target; if ((eventsType = events[type])) { listeners = eventsType.listeners; len = listeners.length; // 移除 fn if (S.isFunction(fn) && len) { for (i = 0,j = 0,t = []; i < len; ++i) { if (fn !== listeners[i].fn || scope !== listeners[i].scope) { t[j++] = listeners[i]; } } eventsType.listeners = t; len = t.length; } // remove(el, type) or fn 已移除光 if (fn === undef || len === 0) { if (!target.isCustomEventTarget) { special = Event.special[type] || { }; if (special.fix !== false) simpleRemove(target, special.fix || type, eventsType.handle); } delete events[type]; } } if (special.destroy) { special.destroy.apply(null, S.makeArray(arguments)); } // remove(el) or type 已移除光 if (type === undef || S.isEmptyObject(events)) { for (type in events) { Event.remove(target, type); } delete cache[id]; removeID(target); } }, _handle: function(target, event) { /* As some listeners may remove themselves from the event, the original array length is dynamic. So, let's make a copy of all listeners, so we are sure we'll call all of them.*/ var listeners = Event.__getListeners(target, event.type); listeners = listeners.slice(0); var ret, gRet, i = 0, len = listeners.length, listener; for (; i < len; ++i) { listener = listeners[i]; ret = listener.fn.call(listener.scope, event); //有一个 false,最终结果就是 false if (gRet !== false) { gRet = ret; } // 和 jQuery 逻辑保持一致 // return false 等价 preventDefault + stopProgation if (ret !== undefined) { event.result = ret; if (ret === false) { event.halt(); } } if (event.isImmediatePropagationStopped) { break; } } return gRet; }, _getCache: function(id) { return cache[id]; }, __getID:getID, _simpleAdd: simpleAdd, _simpleRemove: simpleRemove }; // shorthand Event.on = Event.add; function batch(methodName, targets, types, fn, scope) {//batch方法,在add或者是remove之前做一层批量的处理 // on('#id tag.className', type, fn) if (S.isString(targets)) { targets = S.query(targets);//获取targets对象 } // on([targetA, targetB], type, fn) if (S.isArray(targets)) {//如果有多个targets,那么就在Event对象下面对应的方法下面传入参数,不处理多对象多事件的情况 S.each(targets, function(target) { Event[methodName](target, types, fn, scope); }); return true; } // on(target, 'click focus', fn) if ((types = S.trim(types)) && types.indexOf(SPACE) > 0) {//一个对象有多个事件使用同一个事件函数 S.each(types.split(SPACE), function(type) { Event[methodName](targets, type, fn, scope); }); return true; } } function getID(target) {//getID 如果是一个dom节点或一个对象,就取这个节点的EVENT_GUID属性,否则返回-1 return isValidTarget(target) ? DOM.data(target, EVENT_GUID) : -1; } function setID(target, id) {//setID,如果是一个dom节点或一个对象,就给这个节点加上一个EVENT_GUID属性 if (isValidTarget(target)) { DOM.data(target, EVENT_GUID, id); } } function removeID(target) {//removeID,删除一个dom节点或一个对象的EVENT_GUID属性 DOM.removeData(target, EVENT_GUID); } function isValidTarget(target) {//isValidTarget方法 // 3 - is text node // 8 - is comment node return target && target.nodeType !== 3 && target.nodeType !== 8; } S.Event = Event; });