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;
        },
时间: 2024-07-30 07:45:15

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

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

接下来就是触发事件了.事件触发后的处理函数的分发主要靠两个函数,一个jQuery.event.dispatch,一个是jQuery.event.handlers.这个dispatch会调用handlers,而handlers会返回一个数组,这个数组是符合本次事件条件的所有处理函数对象.dispatch只管执行.那这个handlers是如何运作的呢.绑定在一个元素上面的非代理事件是肯定要被触发的,所以会全数被返回.主要是代理事件的筛选,jQuery会从触发了事件(target所指的元素)的元素一级

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

jQuery的Event模块提供了强大的功能:事件代理,自定义事件,自定义数据等.今天记录一下它实现的原理. 我们都知道,在js的原生事件中,有事件对象和回调函数这两样东西.但是事件对象是只读的,所以jQuery就用了自己的Event对象替代了原生的事件对象,这样就可以实现对事件对象的完全控制,所以才能实现自定义数据.而回调函数的话,每个元素只有一个一样的回调函数,这样方便管理. 下面来看看event对象长什么样. 可以看到jQuery的事件对象其实一开始就只有这么一点东西.其中original

Zepto源码分析-event模块

源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT license. ;(function($){ var _zid = 1, undefined, slice = Array.prototype.slice, isFunction = $.isFunction, isString = function(obj){ return typeof obj

nginx源码分析——event模块

源码:nginx 1.12.0 一.简介 nginx是一款非常受欢迎的软件,具备高性能.模块化可定制的良好特性.之前写了一篇nginx的http模块分析的文章,主要对http处理模块进行了分析讲解,同时也涉及了nginx模块化的内容.至于nginx高性能的原因,希望能够在在这篇文章中就自己对于这方面的理解给大家分享一下. nginx的event处理模型包含两个方面:高效的IO处理函数,事件的异步处理(可选的线程池). 二.IO复用函数 nginx中包含epoll.poll.select.devp

jQuery源码分析--event事件绑定(上)

上文提到,jquery的事件绑定有bind(),delegate()和one()以及live()方式.我用的jQuery2.1.3版本,live()已经被废弃了. bind(),delegate()和one()的内部源码. //7491行 bind: function( types, data, fn ) { return this.on( types, null, data, fn ); }, //7498行 delegate: function( selector, types, data,

jQuery源码分析系列(37) : Ajax 总结

综合前面的分析,我们总结如下3大块: jQuery1.5以后,AJAX模块提供了三个新的方法用于管理.扩展AJAX请求 前置过滤器 jQuery. ajaxPrefilter 请求分发器 jQuery. ajaxTransport 类型转换器 ajaxConvert 为了整体性与扩展性考虑,把整个结构通过Deferred实现异步链式模型,Promise对象可以轻易的绑定成功.失败.进行中三种状态的回调函数,然后通过在状态码在来回调不同的函数就行了 出于同源策略考虑,存在跨域问题,所以ajax内部

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

jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书>结合起来进行学习.推荐读读这本书,你可以从这里和这里下载. 第一部分:检视阅读 1. 收集参考资料:官方文档.书籍.百度/谷歌,专题/博客等,快速的浏览,对涉及的知识点.范围.深度.是否有参考意义等有大致的了解和判断,知道这些文章的作者想要解释或解决什么问题. 第二部分:分析阅读 2. 细读官方文档,官方有非

jQuery源码分析系列(33) : AJAX中的前置过滤器和请求分发器

jQuery1.5以后,AJAX模块提供了三个新的方法用于管理.扩展AJAX请求,分别是: 1.前置过滤器 jQuery. ajaxPrefilter 2.请求分发器 jQuery. ajaxTransport, 3.类型转换器 ajaxConvert 源码结构: jQuery.extend({ /** * 前置过滤器 * @type {[type]} */ ajaxPrefilter: addToPrefiltersOrTransports(prefilters), /** * 请求分发器 *

jQuery源码分析-jQuery中的循环技巧

Js代码   作者:nuysoft/JS攻城师/高云 QQ:47214707 EMail:[email protected] 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 前记:本文收集了jQuery中出现的各种遍历技巧和场景 Js代码   // 简单的for-in(事件) for ( type in events ) { } Js代码   // 缓存length属性,避免每次都去查找length属性,稍微提升遍历速度 // 但是如果遍历HTMLCollection时,性能提升非常