zoukankan      html  css  js  c++  java
  • jQuery源码分析--Event模块(3)

      最后剩下了事件的手动触发了。jQuery提供了两个函数trigger和triggerHandler来手动触发事件,可以触发原生事件和自定义的事件。这个触发不单只会触发有jQuery绑定事件,而且也会触发原生的行内绑定事件。trigger和triggerHander的区别是:
      trgger:会对匹配的所有元素都调用jQuery.event.trrger,而且会冒泡,会触发浏览器默认行为。返回值为jQuery对象
      triggerHandler:只会对第一个匹配的元素调用jQuery.event.trrger,而且不会冒泡,不会触发浏览器默认行为。为函数的返回值
      可以看到都是通过底层的jQuery.event.trrger工具方法来实现。那jQuery.event.trrger是如何工作的呢。

    1. 构造从当前节点到window的一个冒泡路径,用数组来存储。
    2. 遍历这个路径数组,在没有被阻止冒泡的情况下,调用每个节点的jQuery的主监听函数 和 元素的行内监听函数。
    3. 最后用原生的事件触发函数(click,focus)来触发默认行为。并设定一个jQuery.event.triggered标志来标志是触发默认行为,避免再次触发事件。
      最后是源代码。
      trigger: function( event, data, elem, onlyHandlers ) {//event 可以是事件类型、自定义事件对象或jquery事件对象
      
              var i, cur, tmp, bubbleType, ontype, handle, special,
                  eventPath = [ elem || document ],//冒泡路劲
                  type = hasOwn.call( event, "type" ) ? event.type : event,//判断event是对象(自定义和jquery)还是类型字符串
                  namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];//命名空间
      
              cur = tmp = elem = elem || document;//cur指向当前元素的祖先元素
      
              // Don't do events on text and comment nodes
              if ( elem.nodeType === 3 || elem.nodeType === 8 ) {//排除文本节点和注释节点
                  return;
              }
      
              // focus/blur morphs to focusin/out; ensure we're not firing them right now    rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
              if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {//过滤掉foces/blur事件的默认行为,后面统一用focusin/focusout
                  return;
              }
      
              if ( type.indexOf(".") >= 0 ) {//解析事件类型和命名空间并对命名空间排序 
                  // Namespaced trigger; create a regexp to match event type in handle()
                  namespaces = type.split(".");
                  type = namespaces.shift();
                  namespaces.sort();
              }
              ontype = type.indexOf(":") < 0 && "on" + type;//有:号时不调用行内监听事件
      
              // Caller can pass in a jQuery.Event object, Object, or just an event type string
              event = event[ jQuery.expando ] ?//判断是不是jquery监听对象,不是创建。
                  event :
                  new jQuery.Event( type, typeof event === "object" && event );
      
              // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
              event.isTrigger = onlyHandlers ? 2 : 3;
              event.namespace = namespaces.join(".");
              event.namespace_re = event.namespace ?
                  new RegExp( "(^|\.)" + namespaces.join("\.(?:.*\.|)") + "(\.|$)" ) :
                  null;
      
              // Clean up the event in case it is being reused
              event.result = undefined;//最后一个有返回值的函数的返回值
              if ( !event.target ) {//修正target
                  event.target = elem;
              }
      
              // Clone any incoming data and prepend the event, creating the handler arg list
              data = data == null ?//将附加数据(如果有)和事件对象封装成数组。方便apply调用
                  [ event ] :
                  jQuery.makeArray( data, [ event ] );
      
              // Allow special events to draw outside the lines
              special = jQuery.event.special[ type ] || {};
              if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {//先调用修正对象的触发函数来触发
                  return;
              }
      
              // Determine event propagation path in advance, per W3C events spec (#9951)   构造冒泡路劲
              // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
              if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {//排除onlyHandlers=true、load、已经到window对象了
      
                  bubbleType = special.delegateType || type;//优先使用修正对象的属性
                  if ( !rfocusMorph.test( bubbleType + type ) ) {//初始化cur为当前元素的父元素(排除focus/blur)
                      cur = cur.parentNode;
                  }
                  for ( ; cur; cur = cur.parentNode ) {//遍历
                      eventPath.push( cur );
                      tmp = cur;//tmp指向所能到达的最顶层元素
                  }
      
                  // Only add window if we got to document (e.g., not plain obj or detached DOM)
                  if ( tmp === (elem.ownerDocument || document) ) {//如果最顶层是document再添加window
                      eventPath.push( tmp.defaultView || tmp.parentWindow || window );
                  }
              }
      
              // Fire handlers on the event path
              i = 0;
              while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {//遍历冒泡路劲  触发监听函数
      
                  event.type = i > 1 ?
                      bubbleType :
                      special.bindType || type;
      
                  // jQuery handler
                  handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );//取出主监听函数
                  if ( handle ) {//调用主监听函数
                      handle.apply( cur, data );
                  }
      
                  // Native handler
                  handle = ontype && cur[ ontype ];
                  if ( handle && handle.apply && jQuery.acceptData( cur ) ) {//执行行内事件监听函数
                      event.result = handle.apply( cur, data );
                      if ( event.result === false ) {//返回值为false代表阻止默认行为
                          event.preventDefault();
                      }
                  }
              }
              event.type = type;//回复type
      
              // If nobody prevented the default action, do it now
              if ( !onlyHandlers && !event.isDefaultPrevented() ) {//没有阻止默认行为
      
                  if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
                      jQuery.acceptData( elem ) ) {
      
                      // Call a native DOM method on the target with the same name name as the event.
                      // Don't do default actions on window, that's where global variables be (#6170)
                      if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
      
                          // Don't re-trigger an onFOO event when we call its FOO() method  避免再次触发行内监听函数
                          tmp = elem[ ontype ];
      
                          if ( tmp ) {
                              elem[ ontype ] = null;
                          }
      
                          // Prevent re-triggering of the same event, since we already bubbled it above   避免再次触发主函数
                          jQuery.event.triggered = type;
                          elem[ type ]();
                          jQuery.event.triggered = undefined;
      
                          if ( tmp ) {//恢复
                              elem[ ontype ] = tmp;
                          }
                      }
                  }
              }
      
              return event.result;
          },
  • 相关阅读:
    python中使用schedule模块定时执行任务
    python marshmallow库
    shell 脚本根据名称查找进程id会多出来两个id号
    docker随笔(1)
    python实现-kafka作为消息中间件 -实现数据生产和消费-实用的脚本
    python-kafka文档
    mysql文档
    VMware pro15安装centos7
    excel表计算和计算器计算结果不一致
    jmeter安装部署、maven路径配置
  • 原文地址:https://www.cnblogs.com/dq-Leung/p/4341552.html
Copyright © 2011-2022 走看看