我们已经了解过jQuery.event下的方法,回顾一下
jQuery.event = { global: {}, add: function( elem, types, handler, data, selector ) {}, remove: function( elem, types, handler, selector, mappedTypes ) {}, trigger: function( event, data, elem, onlyHandlers ) {}, dispatch: function( event ) {}, handlers: function( event, handlers ) {}, props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), fixHooks: {}, keyHooks: { props: "char charCode key keyCode".split(" "), filter: function( event, original ) {} }, mouseHooks: { props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "), filter: function( event, original ) {} }, fix: function( event ) {}, special: { load: { noBubble: true }, focus: { // Fire native event if possible so blur/focus sequence is correct trigger: function() {}, delegateType: "focusin" }, blur: { trigger: function() {}, delegateType: "focusout" }, click: { trigger: function() {}, _default: function( event ) { return jQuery.nodeName( event.target, "a" ); } }, beforeunload: { postDispatch: function( event ) {} } }, simulate: function( type, elem, event, bubble ) {} }
今天,我们先来了解jQuery.event.add方法
我们先来看源码
/*
elem: 操作的元素
types: 事件类型
handle: 事件触发的方法
data: 事件触发的方法需要的参数
selector: 委托的元素
调用: 比如我们在jquery.fn.on中的调用
jQuery.fn.extend({
on: function(){
...
jQuery.event.add( this, types, fn, data, selector );
...
}
})
*/
add: function( elem, types, handler, data, selector ) { var handleObjIn, eventHandle, tmp, events, t, handleObj, special, handlers, type, namespaces, origType,
/*
获取绑定在elem上的data缓存
*/ elemData = data_priv.get( elem ); //不允许出现文本节或者注释节点。但允许出现空对象{}
if ( !elemData ) { return; }
//这里的handler允许是对象代替handler函数,这里的对象指的是下面的handlerObj。要我说这里有点累赘。干嘛要非得支持这种写法的多样性,增加阅读复杂度。
if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; }
//给handler添加一个guid属性,确保handler函数有唯一ID,之后的查找或者删除可以使用它 if ( !handler.guid ) { handler.guid = jQuery.guid++; } // elemData如果没有events属性,给它加上。第一次才会用上
if ( !(events = elemData.events) ) { events = elemData.events = {}; }
// elemData没有handle属性,给它加上
if ( !(eventHandle = elemData.handle) ) { eventHandle = elemData.handle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events eventHandle.elem = elem; } // 处理用空格分开的多事件操作 types = ( types || "" ).match( core_rnotwhite ) || [""]; t = types.length; while ( t-- ) {
//typenamespace = /^([^.]*)(?:.(.+)|)$/; tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); // There *must* be a type, no attaching namespace-only handlers if ( !type ) { continue; } // 得到特殊处理的事件类型 special = jQuery.event.special[ type ] || {}; // 如果selector有定义,type可能不一样 type = ( selector ? special.delegateType : special.bindType ) || type; // 修正special special = jQuery.event.special[ type ] || {}; // 得到handleObj handleObj = jQuery.extend({ type: type, origType: origType, data: data, handler: handler, guid: handler.guid, selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test( selector ), namespace: namespaces.join(".") }, handleObjIn ); // 初始化elemData.events[type] if ( !(handlers = events[ type ]) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // 在没有special.setup或者special.setup返回false时候,对元素绑定事件 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } } } //如果有special.add,执行special.add if ( special.add ) { special.add.call( elem, handleObj ); //如果handleObj.handler.guid不存在,吧handler.grid赋值给handleObj.handler.guid if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // 把handleObj附加到events[type]数组。对于委托事件,delegateCount++并且添加到数组最前面。否则加到数组后面 if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } // 让elem为空,避免ie内存泄露 elem = null; }
上面我们已经对jQuery.event.add的源码做出相应解释。我们再总结一下
这个方法的作用就是对elem身上的data缓存数据进行添加或者修正。之后的大部分操作都是集中在这个数据缓存elemData上操作。