zoukankan      html  css  js  c++  java
  • jQuery事件处理(一)

    1、jQuery事件绑定的用法:

    $( "elem" ).on( events, [selector], [data], handler );

    events:事件名称,可以是自定义事件名称

    selector:选择器

    data:事件触发时传递给事件处理函数

    handler:事件处理函数

    2、on方法源码分析

    on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
      var origFn, type;

      // 如果types是对象,则说明是传入了多个事件
      if ( typeof types === "object" ) {
        // 如果selector不是string,则说明用户没有传入selector
        if ( typeof selector !== "string" ) {
          // 把selector赋值给data
          data = data || selector;

          // selector置为undefined
          selector = undefined;
        }

        // 遍历types对象中的每一个元素,并递归调用自身
        for ( type in types ) {
          this.on( type, selector, data, types[ type ], one );
        }
        return this;
      }

      // 如果data和fn都为null,说明用户只传了前两个参数

      if ( data == null && fn == null ) {
        // 把selector(第二个参数)赋值给fn
        fn = selector;

        // data和selector置为undefined
        data = selector = undefined;

      // 如果fn为null,说明用户传了三个参数
      } else if ( fn == null ) {

        // 如果selector的类型是string,说明用户没传data
        if ( typeof selector === "string" ) {
          // 把data赋值给fn
          fn = data;

          // 把data置为undefined
          data = undefined;
        } else {
          // 否则的话,说明用户没传selector,而是传了data,将data赋值给fn

          fn = data;

          // 将selector赋值给data
          data = selector;

          // 将selector置为undefined
          selector = undefined;
        }
      }

      // 如果用户传入的事件处理函数是false值,则将事件处理函数赋值为jQuery内部的returnFalse函数
      if ( fn === false ) {
        fn = returnFalse;

      // 如果用户没传回调函数,返回this,this是啥?返回this干嘛?
      } else if ( !fn ) {
        return this;
      }

      // 如果one为1,内部用,暂时没看到用途

      if ( one === 1 ) {
        origFn = fn;
        fn = function( event ) {
          // Can use an empty set, since event contains the info
          jQuery().off( event );
          return origFn.apply( this, arguments );
        };
        // Use same guid so caller can remove using origFn
        fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
      }

      // 遍历this对象,调用jQueryevent对象的add方法处理事件
      return this.each( function() {
        jQuery.event.add( this, types, fn, data, selector );
      });
    },

    通过分析on方法的源码发现,on方法并没有处理事件相关的任何事情,只是对用户传入的参数进行调整,真正处理事件的是event对象

    3、首先看看event对象的构造函数都做了什么

    jQuery.Event = function( src, props ) {
      // 余老板的suggest组件中也用到了这种方法

      // 检测this是不是Event对象,如果不是,new一个Event对象出来,这样就避免了外部new对象
      if ( !(this instanceof jQuery.Event) ) {
        return new jQuery.Event( src, props );
      }

      // 如果有src,并且src有type属性
      if ( src && src.type ) {

        // 定义originalEvent属性并将src赋值给它
        this.originalEvent = src;

        // 定义type属性,并将src.type赋值给它
        this.type = src.type;

        // 定义isDefaultPrevented属性并通过判断事件被阻止冒泡为其赋值
        this.isDefaultPrevented = ( src.defaultPrevented ||
          src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;

      // 否则,将src赋值给type
      } else {
        this.type = src;
      }

      // 如果用户传入props,则扩展Event或者覆盖原有的属性
      if ( props ) {
        jQuery.extend( this, props );
      }

      // 创建一个时间戳??
      this.timeStamp = src && src.timeStamp || jQuery.now();

      // 给这个Event对象一个标记
      this[ jQuery.expando ] = true;
    };

    看event对象的构造函数发现,构造函数做了一些初始化操作。在看一下event对象封装的一些方法。

    4、jQuery的event对象

      jQuery的event对象提供了如下方法和属性:

        {

          add : function(){},

          remove : function(){},

          trigger : function(){},

          dispatch : function(){},

          handlers : function(){},

          fix: function(){},

          simulate : function(){},

          global : {},

          props : {},

          fixHooks : {},

          keyHooks : {},

          mouseHooks : {},

          special : {}

        }

      首先看add方法:

      add: function( elem, types, handler, data, selector ) {

        var handleObjIn, eventHandle, tmp,
          events, t, handleObj,
          special, handlers, type, namespaces, origType,
          elemData = data_priv.get( elem );

        // 涉及到jQuery的另外一个大的方面:缓存机制。或许我应该先看缓存机制的。。。

        // 不为text、comment节点绑定数据,直接返回
        if ( !elemData ) {
          return;
        }

        // 如果handler是一个有handler属性或方法的对象,则进行一些转移赋值操作
        if ( handler.handler ) {
          handleObjIn = handler;
          handler = handleObjIn.handler;
          selector = handleObjIn.selector;
        }

        // 检查handler是否有一个唯一的id,方便之后查找和删除
        if ( !handler.guid ) {

          // 如果没有就为其设定一个唯一id
          handler.guid = jQuery.guid++;
        }

        // 如果elemData中没有events对象,则为其定义events属性并赋值为空对象
        if ( !(events = elemData.events) ) {
          events = elemData.events = {};
        }

        // 如果elemData中没有handle对象
        if ( !(eventHandle = elemData.handle) ) {

          // 为elemData定义一个handle方法(事件处理函数)
          eventHandle = elemData.handle = function( e ) {
            // 有点迷糊。。。
            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 = ( types || "" ).match( core_rnotwhite ) || [""];
          t = types.length;
          while ( t-- ) {
            tmp = rtypenamespace.exec( types[t] ) || [];
            type = origType = tmp[1];
            namespaces = ( tmp[2] || "" ).split( "." ).sort();

            if ( !type ) {
              continue;
          }

          // 事件是否会改变当前状态,如果是则使用特殊事件,看event的special属性。。。
          special = jQuery.event.special[ type ] || {};

          // 根据是否有selector判断使用哪种特殊事件(看完特殊事件再过来看这个地方)
          type = ( selector ? special.delegateType : special.bindType ) || type;

          // 根据新的type获取新的special
          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 );

          // 如果是第一次调用,初始化事件处理队列(将同一事件的处理函数放入数组中)
          if ( !(handlers = events[ type ]) ) {
            handlers = events[ type ] = [];
            handlers.delegateCount = 0;

            // 如果获取特殊事件监听方法失败,则使用addEventListener添加事件(抛弃attachEvent了吗?)
            if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
              if ( elem.addEventListener ) {
                elem.addEventListener( type, eventHandle, false );
              }
            }
          }

          // 使用special的add方法进行处理

          if ( special.add ) {

            // 添加事件
            special.add.call( elem, handleObj );

            // 设置handleObj中的handler属性的id

            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;
        }

        // 将elem清空,等待回收,避免内存泄漏
        elem = null;
      },

  • 相关阅读:
    leetcode 116,117,129,145,199,230,337
    leetcode 897,JZ68,JZ17,95,96,105,113,114
    leetcode 404,530,543,563,572,589,617,637,700
    leetcode 397,784,898,100,101,104,108,110,111,112,226,235,257
    leetcode 78,137,187,260,393
    leetcode 169,190,191,665,342,476,1290
    leetcode 44,56,179,274,853,948
    leetcode 55,134,376,406,435,452,621
    leetcode 122,392,455,605,860,874,1005
    leetcode (堆->hard) 23,218,239,295,407,786
  • 原文地址:https://www.cnblogs.com/charling/p/3464362.html
Copyright © 2011-2022 走看看