研究一下jQuery的事件模型。

1.定义

    jQuery.event={
        add:function(){},
        remove:function(){},
        triggle:function(){},
        handle:function(){},
        fix:function(){},
   
        global:{},
        props:"XXX YYY zzz".split(" "),
        guid:IE8,
        proxy:jQuery.proxy,
        special:{
            ready: {
                setup:jQuery.bindReady,
                teardown: jQuery.noop       
            },
            live:{
                add:function(){},
                remove:function(){}       
            },
            beforeunload:{
                setup:function(){},
                teardown:function(){}       
            }   
   
        }
    }

    jQuery.event为一个固有对象,其里面包含各种静态工具方法。用户调用bind   unbind  one等等函数时,其内部实现必然会调用这些工具方法。
    该对象还有一些属性后文介绍。现在按照普通的用法看看事件机制是如何构成的。

2.bind  的解析过程

    当我们写
       
        $("p").bind("click", function(e){})
       
    jQuery引擎到底做了什么事情?
    首先,选择器选择到了一个jQuery对象(其实就是DOM对象外加一些其他jQuery放进去的属性),在该对象上调用bind方法。
    jQuery对象上的方法,不同于jQuery那个函数对象里面的方法,就如在上一篇文章《工具方法》中所说的,jQuery对象的方法必需都要在原型里面注册过才行。
   
    看bind方法什么时候加入到jQuery.prototype里面去的。搜索“bind: function”企图看bind方法的定义,只找到unbind的定义。原来bind 和 one在上面一个语句块里面一起定义的。
   
        jQuery.each(["bind", "one"], function( i, name ) {
            jQuery.fn[ name ] = function( type, data, fn ) {
                STATEMENTS;
                return this;
            };
        });
   
    看到jQuery.fn就明白了。由上一篇文章所述,jQuery.fn已经与jQuery的原型关联起来了,往fn里面放任何方法都同时被prototype拥有。
    现在可知,此处注册了2个方法bind 和one 。 最后return this 依然是为了链式操作。
   
    看STATEMENTS;函数体里面到底作了什么。
   
        jQuery.fn[ name ] = function( type, data, fn ) {
            // Handle object literals
            if ( typeof type === "object" ) {   //一般情况下是 typeof type = "string"
                for ( var key in type ) {
                    this[ name ](key, data, type[key], fn);
                }
                return this;
            }
       
            if ( jQuery.isFunction( data ) || data === false ) {
                fn = data;
                data = undefined;
            }

            var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
                jQuery( this ).unbind( event, handler );
                return fn.apply( this, arguments );
            }) : fn;

            if ( type === "unload" && name !== "one" ) {
                this.one( type, data, fn );

            } else {
                for ( var i = 0, l = this.length; i < l; i++ ) {
                    jQuery.event.add( this[i], type, handler, data );   
                }
            }

            return this;   
        };
       
       
   
    由bind的用法我们知道,该bind方法接受2个参数  “click”  和  function(e){} 也就是    type(事件类型) 和fn(回调函数)。
    如果是one来绑定事件,另说。
    如果是bind来作,则主要操作在最后一个else里面。
    this.length是什么?我们在《工具方法》一章说过,jQuery对象是类数组,有key为0,1,2,3...的属性值,还有一个名为length的属性值,指示的就是前面的数数。
    length就是该jQuery对象包含的Element元素的个数。也就是说对每一个Element元素调用一个add的方法。
   
        jQuery.event.add( this[i], type, handler, data ); 
       
    jQuery.event.add()是一个静态工具方法。不用看代码就可以猜到大致作用:在this[i]指示的Element元素上监听名字为type的事件类型,其回调函数为handler。data另看。
   
    其关键代码如下:
   
        add: function( elem, types, handler, data ) {   
   
            //处理ie兼容性;
   
            //唯一guid
       
            //这个方法取到elem 的私有数据expando。看来所有事件处理的东西都放在对象的私有属性expando上了。
            //每个elem对象有一个属性,名与"jQueryXXXX"类似,是自动生成的,(在运行期,所有elem对象的这个属性名都一样为jQuery.expando)
            //这个属性的值,是一个唯一的自增的id,它对应一个全局数组对象jQuery.cache的一个条目,那个条目值,也是一个对象,即为该elem
            //对象的私有数据保存的地方。
   
            var elemData = jQuery.data( elem );
            var events = elemDate['event'] // events是一个对象。
            var eventHandle = elemData.handle   //eventHandle是一个方法。
            eventHandle.elem = elem;
            handleObj = {
                handler : handler;
                data : data
            }   
            handleObj.type = tpe;
   
            //把handleObj 塞到 handlers里头。 handlers是events的一个属性type的值。

        }   
       

    事件及其处理函数被当作Elemen元素的私有数据,维护在cache里面了。
   
   
      
    上图是追踪jQuery对象里面Element对象,绑定事件的图示。其中第二列中4个不应该是jQuery对象,应该是Element对象才对。

      
posted on 2011-06-03 22:39  chenmouren  阅读(1720)  评论(0)    收藏  举报