我们都知道jQuery的事件其思想来源于Dean Edwards的addEvent,通过源码我们知道jQuery在为元素绑定事件时,每种类型的事件(click,blur)时只绑定了一次对应类型的事件处理方法,实际的方法是存在jQuery的缓存系统中的,这样做的好处我就不多说了,绑定方法的函数为add方法,在执行事件的时,通过handers在缓存系统中获取事件列表,然后通过dispatch函数来执行对应的事件。
jQuery.event = {
add: function( elem, types, handler, data, selector ) { var tmp, events, t, handleObjIn, special, eventHandle, handleObj, handlers, type, namespaces, origType, elemData = jQuery._data( elem );//从缓存系统中获取对应的事件数据 // 如果不存在事件数据则直接退出 if ( !elemData ) { return; } // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; } // 为事件添加标识 if ( !handler.guid ) { handler.guid = jQuery.guid++; } //初始化事件对象数据 if ( !(events = elemData.events) ) { events = elemData.events = {}; } //每种事件类型只绑定一次事件(eventHanle) 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 !== strundefined && (!e || jQuery.event.triggered !== e.type) ? //通过dispatch来触发事件的执行,eventHandle.elem来绑定当前元素,防止this指向错误(attachEvent中this会指向window的bug) 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; } //多个事件的绑定 // Handle multiple events separated by a space types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; while ( t-- ) { 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; } // If event changes its type, use the special event handlers for the changed type special = jQuery.event.special[ type ] || {}; // If selector defined, determine special event api type, otherwise given type type = ( selector ? special.delegateType : special.bindType ) || type; // Update special based on newly reset type special = jQuery.event.special[ type ] || {}; //将事件组合成一个事件对象 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 ); //handlers对应事件类型的事件列表 if ( !(handlers = events[ type ]) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { //真正绑定事件的地方,只绑定eventHandle if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } //特殊事件的处理 if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // 将事件加入事件列表中 if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } //表示事件曾经使用过,用于事件优化 jQuery.event.global[ type ] = true; } // 防止ie内存溢出 elem = null; }, remove: function( elem, types, handler, selector, mappedTypes ) { //为元素移除事件 }, trigger: function( event, data, elem, onlyHandlers ) { //执行事件 }, dispatch: function( event ) { //分配事件(在执行方法时执行) }, handlers: function( event, handlers ) { //获取缓存系统中对应事件类型的事件列表 } } //其实我们为每种事件绑定的方式是这样的 //通过dispatch来执行对应的事件 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 !== strundefined && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }
好了,jQuery的绑定函数原理先介绍到这里。下次继续!一天一点,滴水汇河!