jQuery学习-事件之绑定事件(一)

      我们都知道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的绑定函数原理先介绍到这里。下次继续!一天一点,滴水汇河!

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。