最后剩下了事件的手动触发了。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;
    },

jQuery源码分析--Event模块(3)的更多相关文章

  1. jQuery源码分析--Event模块(2)

    接下来就是触发事件了.事件触发后的处理函数的分发主要靠两个函数,一个jQuery.event.dispatch,一个是jQuery.event.handlers.这个dispatch会调用handle ...

  2. jQuery源码分析--Event模块(1)

    jQuery的Event模块提供了强大的功能:事件代理,自定义事件,自定义数据等.今天记录一下它实现的原理. 我们都知道,在js的原生事件中,有事件对象和回调函数这两样东西.但是事件对象是只读的,所以 ...

  3. Zepto源码分析-event模块

    源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT l ...

  4. nginx源码分析——event模块

    源码:nginx 1.12.0   一.简介      nginx是一款非常受欢迎的软件,具备高性能.模块化可定制的良好特性.之前写了一篇nginx的http模块分析的文章,主要对http处理模块进行 ...

  5. zepto源码分析·event模块

    准备知识 事件的本质就是发布/订阅模式,dom事件也不例外:先简单说明下发布/订阅模式,dom事件api和兼容性 发布/订阅模式 所谓发布/订阅模式,用一个形象的比喻就是买房的人订阅楼房消息,售楼处发 ...

  6. 读Zepto源码之Event模块

    Event 模块是 Zepto 必备的模块之一,由于对 Event Api 不太熟,Event 对象也比较复杂,所以乍一看 Event 模块的源码,有点懵,细看下去,其实也不太复杂. 读Zepto源码 ...

  7. [转] jQuery源码分析-如何做jQuery源码分析

    jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ...

  8. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

  9. [转]jQuery源码分析系列

    文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...

随机推荐

  1. 【Redis】php+redis实现消息队列

    在项目中使用消息队列一般是有如下几个原因: 把瞬间服务器的请求处理换成异步处理,缓解服务器的压力 实现数据顺序排列获取 redis实现消息队列步骤如下: 1).redis函数rpush,lpop 2) ...

  2. RDO部署多节点OpenStack Havana(OVS+GRE)

    RDO是由红帽RedHat公司推出的部署OpenStack集群的一个基于Puppet的部署工具,可以很快地通过RDO部署一套复杂的OpenStack环境,当前的RDO默认情况下,使用Neutron进行 ...

  3. JQuery中$.ajax()方法参数详解 转载

    url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. type: 要求为String类型的参数,请求方式(post或get)默认为get.注意其他http请求方法,例如put和 ...

  4. 【黑金ZYNQ7000系列原创视频教程】03.体验FPGA里的ARM——裸机helloworld实验

    黑金论坛地址: http://www.heijin.org/forum.php?mod=viewthread&tid=36637&extra=page%3D1 爱奇艺地址: http: ...

  5. 【BZOJ5099】[POI2018]Pionek 几何+双指针

    [BZOJ5099][POI2018]Pionek Description 在无限大的二维平面的原点(0,0)放置着一个棋子.你有n条可用的移动指令,每条指令可以用一个二维整数向量表示.每条指令最多只 ...

  6. Tomcat 400错误 问题集锦

    1.前后台参数类型不一致 上图错误提示就是客户端发送的请求不能找到你的具体的页面或者地址,这是Spring MVC抛出的错误,这样我们就要进行参数的检查,一定是JSP提交的参数和Controller里 ...

  7. 170616、解决 java.lang.IllegalArgumentException: No converter found for return value of type: class java.util.ArrayList

    报错截图: 原因:搭建项目的时候,springmvc默认是没有对象转换成json的转换器的,需要手动添加jackson依赖. 解决步骤: 1.添加jackson依赖到pom.xml <!-- j ...

  8. ABP 样板开发框架系列

    --ABP 官网与源码 http://www.aspnetboilerplate.com/ https://github.com/aspnetboilerplate --pdf和docx 文档 htt ...

  9. Oracle SQL开发 之 Select语句完整的执行顺序

    查询语句语法: Select 属性 From 表 Where 条件 Group by 分组条件 Having 分组选择条件 Order by 排序条件 1.from子句组装来自不同数据源的数据: 2. ...

  10. HotSpot VM

    1.4.2 Sun HotSpot VM_深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)_红黑联盟读书频道 http://book.2cto.com/201306/25434.html 提 ...