jquery事件委托详解

jQuery事件委托处理流程



  上一章分析jQuery.event.add的时候已经分析了事件绑定,再把绑定的部分源码抽出来

if ( !(eventHandle = elemData.handle) ) {
        eventHandle = elemData.handle = function( e ) {
            //当一个事件被调用后页面已经卸载,则放弃jQuery.event.trigger()的第二个事件,
            return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
            jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
            undefined;
        };
        //将elem作为handle函数的一个特征防止ie非本地事件引起的内存泄露
        eventHandle.elem = elem;
    }
    ...
    //非自定义事件,如果special事件处理器返回false,则只能使用addEventListener/attachEvent
    if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
    //给元素绑定全局事件
        if ( elem.addEventListener ) {
             elem.addEventListener( type, eventHandle, false );

        } else if ( elem.attachEvent ) {
             elem.attachEvent( "on" + type, eventHandle );
        }
    }

  绑定到elem上的事件处理是eventHandle,最终执行eventHandle的时候实际执行的是事件调度jQuery.event.dispatch。事件调度的的流程实际上就是处理委托事件的流程,因为本节点的响应处理最终会被附加到委托处理列表后面。

  事件调度流程为

  1. 从本地事件对象event构造一个可写的jQuery.Event对象。并用这个对象替换掉传参中的本地事件对象

//从本地事件对象构造一个可写的jQuery.Event
event = jQuery.event.fix( event );...//使用修正过得jQuery.Event而不是(只读的)本地事件args[0] = event;event.delegateTarget = this;

  本地事件event的结构如下

  

  使用本地事件构造的新事件对象jQuery.Event结构如下

  

  其中originalEvent属性的值便是本地事件对象。构造的这个事件对象有很多属性都是直接从本地事件对象中抽出来的。

  2. 获取当前节点缓存中对应事件类型的事件处理列表

        handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],

  事件处理列表的的顺序是委托事件处理在前面,最后才是直接绑定到当前节点的事件处理。

  3. 用当前节点替换jQuery.event.handlers的调用者并执行之,获取到符合要求的委托处理函数队列(这个队列最后会加上绑定到节点本身的处理事件)

//获取指定的事件处理队列,主要使用event.target事件源节点不断循环往上查找父节点,
//看些节点和是否在handlers中的选择器对应的节点中
handlerQueue = jQuery.event.handlers.call( this, event, handlers );

  详细分析一下jQuery.event.handlers中获取符合要求的委托处理函数队列。

  jQuery.event.handlers先将委托事件处理取出来放在处理队列handlerQueue中。

  查找的过程是:先取出事件源cur = event.target;然后在确定有委托处理的情况下从事件源开始往他的祖先节点查询,直到this节点以下,遍历事件源到this节点(不包含this节点)的每个节点,在遍历中二次遍历委托事件列表中的每一个委托事件处理所指定的响应节点(委托事件处理对象的selector所指定)是否包含当前遍历节点(事件源到this节点中的当前节点)【handleObj.needsContext ?jQuery( sel, this ).index( cur ) >= 0 :jQuery.find( sel, this, null, [ cur ] ).length】,如果包含则往事件处理队列handlerQueue中压入该委托处理。源码如下

if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
  //冒泡父节点,找到匹配的委托事件存入handlerQueue队列
  for ( ; cur != this; cur = cur.parentNode || this ) {
    if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
      matches = [];
      for ( i = 0; i < delegateCount; i++ ) {        // 避免和Object.prototype属性冲突(#13203)        sel = handleObj.selector + " ";        if ( matches[ sel ] === undefined ) {          matches[ sel ] = handleObj.needsContext ?          jQuery( sel, this ).index( cur ) >= 0 :          jQuery.find( sel, this, null, [ cur ] ).length;        }                  if ( matches[ sel ] ) {          matches.push( handleObj );        }      }      //添加委托处理到队列中      if ( matches.length ) {        handlerQueue.push({ elem: cur, handlers: matches });      }    }  }}

  最后将直接绑定到当前节点的处理也压入执行

//添加直接绑定的事件到handlerQueue队列中
if ( delegateCount < handlers.length ) {
  handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
}

  

  4. 执行事件处理队列handlerQueue中的处理函数

//先运行代理,他们可能是阻止冒泡的,我们可以利用这一点
i = 0;
while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
        event.currentTarget = matched.elem;

        j = 0;
        while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {

            //触发事件的条件:1)没有命名空间,或
            // 2)有命名空间的子集或等于那些边界事件(他们两者都可以没有命名空间)
            if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {

                event.handleObj = handleObj;
                event.data = handleObj.data;
                //执行
                ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
                .apply( matched.elem, args );

                if ( ret !== undefined ) {
                    if ( (event.result = ret) === false ) {
                        event.preventDefault();
                        event.stopPropagation();
                    }
                }
            }
        }
    }

  此篇文章是帮助理解jQuery.event.handlers中获取符合要求的委托处理函数队列的,自己看源码一直不太明白,看@chua1989大佬的jQuery-1.9.1源码分析系列(十) 事件系统——事件委托关于这一段也没讲太清,自己通过各种调试一步一步总算理解了,借大佬的文章再梳理一遍,防止日后忘记特此记录,致敬chua1989大佬

原文地址:https://www.cnblogs.com/changzz/p/12015768.html

时间: 2024-08-28 02:19:15

jquery事件委托详解的相关文章

jQuery 事件用法详解

jQuery 事件用法详解 目录 简介 实现原理 事件操作 绑定事件 解除事件 触发事件 事件委托 事件操作进阶 阻止默认事件 阻止事件传播 阻止事件向后执行 命名空间 自定义事件 事件队列 jquery中文文档 简介 jquery 之所以成为最受欢迎的前端库,很大一部分是得益于它的事件具有良好的语义,优秀的兼容性,并且便于管理和扩展. 在这里我会介绍 jquery 事件的一些比较基础的用法. 实现原理 jquery 事件脱胎于浏览器的 addEventListener (W3) 和 attac

事件委托详解

基本概念 事件委托,通俗地来讲,就是把一个元素响应事件(click.keydown......)的函数委托到另一个元素: 一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数. 举个例子,比如一个宿舍的同学同时快递到了,一种方法就是他们都傻傻地一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发

JavaScript 事件委托详解

基本概念 事件委托,通俗地来讲,就是把一个元素响应事件(click.keydown......)的函数委托到另一个元素: 一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数. 举个例子,比如一个宿舍的同学同时快递到了,一种方法就是他们都傻傻地一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发

JS中的事件委托详解(未完)

什么是JS事件委托呢? 首先,我们要明确什么是事件:所谓的事件就是像:onclick,onmouseover,onmouseover.......这些事件,那委托呢?就是指原来发生在这些事件上的元素,加到其它的元素身上来完成. JS事件委托的原理:就是利用冒泡的原理,把事件加到父级或是父级的父级身上,来触发执行操作. 使用事件委托的优势:1)提高性能: 2)新添加的元素也会有之前加的事件: 下面我们用例子来说明一下:点击改变li的背景颜色 HTML部分: 1 <ul id="ul1&quo

Jquery ajax 参数 详解

Jquery ajax 参数主要如下: url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. type: 要求为String类型的参数,请求方式(post或get)默认为get.注意其他http请求方法,例如put和 delete也可以使用,但仅部分浏览器支持. timeout: 要求为Number类型的参数,设置请求超时时间(毫秒).此设置将覆盖$.ajaxSetup()方法的全局设 置. async:要求为Boolean类型的参数,默认设置为true,所有请求均为异步

.Net委托详解

搬运自http://wurang.me/2014/04/22/delegate.html [什么是委托] 委托是对函数的引用,它是一个引用类型,类似c/cpp中的函数指针.但它是类型安全的. 委托是一个类,定义了方法的类型,可以将方法当做另一个方法的参数传递. 委托就是一个安全的函数指针,用来执行函数方法的东西. [如何使用委托] 在.Net框架下,委托的使用方法经历了多次改变. 最初委托的使用方法如下: public delegate string MyDelegate(string name

cocos2dx+lua注册事件函数详解 事件

coocs2dx 版本 3.1.1 registerScriptTouchHandler             注册触屏事件 registerScriptTapHandler                  注册点击事件 registerScriptHandler                         注册基本事件 包括 触屏 层的进入 退出 事件 registerScriptKeypadHandler           注册键盘事件 registerScriptAccelera

jQuery datepicker参数 详解

DatePicker支持鼠标点选日期,同时还可以通过键盘控制选择: page up/down - 上一月.下一月 ctrl+page up/down - 上一年.下一年 ctrl+home - 当前月或最后一次打开的日期 ctrl+left/right - 上一天.下一天 ctrl+up/down - 上一周.下一周 enter - 确定选择日期 ctrl+end - 关闭并清除已选择的日期 escape - 关闭并取消选择 实用功能: $.datepicker.setDefaults( set

jQuery的观察者模式详解 转载

jQuery的观察者模式详解 投稿:hebedich 本文主要是介绍了jQuery中on方法及trigger方法,以及围绕这个方法来体验的观察者模式,是篇非常不错的文章,对我们理解观察者模式很有帮助. undefined undefined ■ on方法绑定内置事件,自然触发 比如,我们给页面的body元素绑定一个click事件,这样写. <head> <meta http-equiv="Content-Type" content="text/html; c