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大佬

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

  1. jQuery 事件用法详解

    jQuery 事件用法详解 目录 简介 实现原理 事件操作 绑定事件 解除事件 触发事件 事件委托 事件操作进阶 阻止默认事件 阻止事件传播 阻止事件向后执行 命名空间 自定义事件 事件队列 jque ...

  2. JavaScript 事件委托详解

    基本概念 事件委托,通俗地来讲,就是把一个元素响应事件(click.keydown......)的函数委托到另一个元素: 一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事 ...

  3. js中的事件委托详解

    概述: 那什么叫事件委托呢?它还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件.那这是什么意思呢?网上的各位 ...

  4. C#事件与委托详解

    from https://www.cnblogs.com/sjqq/p/6917497.html C#事件与委托详解[精华 多看看] Delegatedelegate是C#中的一种类型,它实际上是一个 ...

  5. 委托与事件代码详解与(Object sender,EventArgs e)详解

    委托与事件代码详解 using System;using System.Collections.Generic;using System.Text; namespace @Delegate //自定义 ...

  6. jQuery.ready() 函数详解

    jQuery.ready() 函数详解 ready()函数用于在当前文档结构载入完毕后立即执行指定的函数. 该函数的作用相当于window.onload事件. 你可以多次调用该函数,从而绑定多个函数, ...

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

    coocs2dx 版本 3.1.1 registerScriptTouchHandler             注册触屏事件 registerScriptTapHandler             ...

  8. jQuery的观察者模式详解 转载

    jQuery的观察者模式详解 投稿:hebedich 本文主要是介绍了jQuery中on方法及trigger方法,以及围绕这个方法来体验的观察者模式,是篇非常不错的文章,对我们理解观察者模式很有帮助. ...

  9. jquery的css详解(二)

    jq的工具方法style用于设置样式,jq的实例方法css在设置样式时就是调用的它,接下来分析一下源码. jQuery.extend({ ............................ st ...

随机推荐

  1. MySQL远程连接和备份还原

    连接远程数据库 mysql -h 数据库地址 -P 端口号 -u 用户名 -p mysql -h -u root -p 备份数据库, 热备份 mysqldump -h 127.0.0.1 -u roo ...

  2. 从0开始学爬虫10之urllib和requests库与github/api的交互

    urllib库的使用 # coding=utf-8 import urllib2 import urllib # htpbin模拟的环境 URL_IP="http://10.11.0.215 ...

  3. matlab基本函数randperm end数组索引

    一起来学演化计算-matlab基本函数randperm end数组索引 觉得有用的话,欢迎一起讨论相互学习~Follow Me 随机排列 语法 p = randperm(n) p = randperm ...

  4. Oracle索引 详解

    作者:Dave 一.索引介绍 1.1 索引的创建语法: CREATE UNIUQE | BITMAP INDEX <schema>.<index_name> ON <sc ...

  5. LeetCode_374. Guess Number Higher or Lower

    374. Guess Number Higher or Lower Easy We are playing the Guess Game. The game is as follows: I pick ...

  6. HTTP请求重复发送

    帖子地址 http://bbs.csdn.net/topics/390831787 解决方案:1.  java -Dsun.net.http.retryPost=false 2. 换用apche ht ...

  7. IIS7(Windows7)下最简单最强安装多版本PHP支持环境

    最近调试程序,要在PHP5.2和5.3之间换来换去,而习惯了windows下的开发,就琢磨怎么在iis下安装多版本支持,赫然发现其实微软都为我们准备了好工具. 微软对PHP的支持越来越强,这点在IIS ...

  8. Java基础教程:多线程杂谈——Volatile

    Java基础教程:多线程杂谈——Volatile 引入Volatile Java语言提供了一种稍弱的同步机制,即Volatile变量,用来确保将变量的更新操作通知到其他线程.当把变量声明为Volati ...

  9. Java学习,从入门到放弃(一)SpringMVC+Maven+Mybits 多种数据库配置(mysql+sqlserver)AOP方式

    多数据库配置需求有两种,一种是因为项目太大,访问量太高,不得不分布多个数据库减轻访问压力,比较多的应用就是读写分离:另一种就是原本不同的两个数据库业务现在要整合到一起,甚至连数据库都不一样,一个mys ...

  10. AWS 架构最佳实践概述(十一)

    AWS 架构最佳实践 AWS合理架构的框架支柱 安全性 - 保护并监控系统 能够保护信息.系统和资产 通过风险评估和缓解策略 可靠性 - 从故障中恢复并减少中断 从基础设施或服务故障中恢复 动态获取计 ...