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

    1、通过一步步调试的的方法观察了一下存放到cache中的事件及其处理程序的数据格式:

    {
      events : { // 根据事件类型存放添加到该元素上的所有事件,下面以click为例
        click : [ // click 事件类型。已数组的形式,按绑定的先后循序存放不同的事件处理函数相关内容(已对象的形式)
          {
            data : "", // 事件绑定时传入的data
                           guid : 1, // jQuery分配的事件的id,用来查找对应的事件,以便删除或进行其它操作
                           namespace : "", // 事件的命名空间
                           needsContext : undefined, // 所需要的环境(暂时不知道是干嘛的)
                           origType : "click", // 原始类型(用户绑定时候的类型,jQuery内部可能会对其进行替换)
                           select : undefined, // 选择器,选择在哪个元素上触发
                           type : "click", // 事件类型
                           handler : function(){} // 用户绑定的事件处理函数。jQuery分类了一个guid作为它的属性
                     }
                ],
                delegateCount : 0 // (暂时不知道是干嘛的)

      },
          handle : function(){} // handle是所有事件类型的触发入口,该方法绑定到了addEventListener的回调上。当事件触发时,首先触发该方法。有一个elem属性
    };

    2、同时记录了一下jQuery封装之后的event对象中的属性和方法。以click事件对象为例。

    event = {
      jQuery121234343 : true, // 标记该事件对象为jQuery封装后的事件对象
      type : "click",
      altkey : false, // 当事件被触发时,alt键是否被按下
      bubbles : true, // 事件是否是起泡事件类型
      button : 0, // 事件触发时,哪个鼠标按钮被按下了
      buttons : 0,
      cancelable : true, // 是否可以取消默认动作
      clientX : 0, // 事件触发时鼠标指针的横坐标
      clientY : 0, // 事件触发时鼠标指针的纵坐标
      ctrlKey : false, // 事件触发时,ctrKey是否被按下
      currentTarget : div(dom), // 触发该事件的元素
      eventPhase : 2, // 事件传播的当前阶段
      metaKey : false, // meta键是否被按下
      offsetX : , // 发生时间的地点在事件触发元素中的横坐标
      offsetY : , // 发生时间的地点在事件触发元素中的纵坐标
      originalEvent : , // 原事件对象
      pageX : , // 距离文档左边缘的鼠标位置
      pageY : , // 距离文档上边缘的鼠标位置
      screenX : , // 以屏幕为基准的鼠标的横坐标
      screenY : , // 以屏幕为基准的鼠标的纵坐标
      shiftKey : , // 当事件触发时,shiftKey是否被按下
      target : div(dom), // 目标元素
      which : , // 按了哪个键或者按钮
      isDefaultPrevented : function(){},
      isImmediatePropagationStopped : function(){},
      isPropagationStopped : function(){},
      preventDefault : function(){},
      stopImmediatePropagation : function(){},
      stopPropagation : function(){}
    }

    3、通过这几天的读源码和查资料,对事件处理机制已经有了大致的理解,继续梳理一下off、one、trigger的内部逻辑,这三个暴露的接口内部事件是通过 jQuery.event的remove、add和trigger实现的。加下来重点看下remove。(trigger的事件方法和通过事件监听触发思路基本一致,源码不再分析)

      remove: function( elem, types, handler, selector, mappedTypes ) {   
        var j, origCount, tmp,
          events, t, handleObj,
          special, handlers, type, namespaces, origType,

          // 取出存放在cache中的该元素相关的所有事件及事件相关信息
          elemData = data_priv.hasData( elem ) && data_priv.get( elem );
        // 如果不存在,或者没有events属性,说明没有绑定任何事件,直接返回
        if ( !elemData || !(events = elemData.events) ) {
          return;
        }
        // 对用户传入的事件类型字符串进行裁切
        types = ( types || "" ).match( core_rnotwhite ) || [""];
        t = types.length;

        // 遍历裁切后得到的所有事件类型
        while ( t-- ) {

          // 拆分事件命名空间
          tmp = rtypenamespace.exec( types[t] ) || [];

          // 得到原始命名空间,也就是第一个点号前面的字符
          type = origType = tmp[1];

          // 得到子命名空间
          namespaces = ( tmp[2] || "" ).split( "." ).sort();

                // 如果没有传入type,则删除该元素上的所有的事件
                if ( !type ) {
                    for ( type in events ) {
                        jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
                    }
                    continue;
                }
        // 得到特殊事件类型的处理方法
        special = jQuery.event.special[ type ] || {};
        type = ( selector ? special.delegateType : special.bindType ) || type;

        // 得到该事件类型的所有事件处理方法
        handlers = events[ type ] || [];
                tmp = tmp[2] && new RegExp( "(^|\.)" + namespaces.join("\.(?:.*\.|)") + "(\.|$)" );

        // 得到该事件类型的所有处理函数的长度
                origCount = j = handlers.length;

        // 对其进行遍历,删除匹配到的事件处理函数
                while ( j-- ) {
                    handleObj = handlers[ j ];

          // 如果类型一致、id一致、在命名空间内、选择器(事件触发的元素)一致,则删除该项
                    if ( ( mappedTypes || origType === handleObj.origType ) &&
                        ( !handler || handler.guid === handleObj.guid ) &&
                        ( !tmp || tmp.test( handleObj.namespace ) ) &&
                        ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
                           handlers.splice( j, 1 );
             // 如果被删除的这一项有selector,说明使用了事件代理,将事件代理的数量减一
                          if ( handleObj.selector ) {
                              handlers.delegateCount--;
                          }

             // 对特殊事件的处理
                          if ( special.remove ) {
                              special.remove.call( elem, handleObj );
                          }
                      }
          }

          // 一些特殊处理(暂不理解)
                  if ( origCount && !handlers.length ) {
                      if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
                          jQuery.removeEvent( elem, type, elemData.handle );
                      }

                      delete events[ type ];
                  }
              }

              // 如果事件全部被清除了,则同时也删掉事件回调的入口和事件存放的容器
              if ( jQuery.isEmptyObject( events ) ) {
                  delete elemData.handle;
                  data_priv.remove( elem, "events" );
              }
          },

  • 相关阅读:
    BZOJ 1101: [POI2007]Zap [莫比乌斯反演]
    磁盘I/O高居不下,通过什么来查看占用I/O的进程?
    jmeter中特殊的时间处理方式
    Fiddler抓包工具版面认识(一)
    Jmeter 时间函数工具汇总
    Jmeter之__CSVRead随机读取变量
    jmeter配置元件之计数器
    Jmeter全局变量设置
    数据驱动和关键字驱动
    sqlmap工具命令行的含义
  • 原文地址:https://www.cnblogs.com/charling/p/3475880.html
Copyright © 2011-2022 走看看