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大佬。
jquery事件委托详解的更多相关文章
- jQuery 事件用法详解
jQuery 事件用法详解 目录 简介 实现原理 事件操作 绑定事件 解除事件 触发事件 事件委托 事件操作进阶 阻止默认事件 阻止事件传播 阻止事件向后执行 命名空间 自定义事件 事件队列 jque ...
- JavaScript 事件委托详解
基本概念 事件委托,通俗地来讲,就是把一个元素响应事件(click.keydown......)的函数委托到另一个元素: 一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事 ...
- js中的事件委托详解
概述: 那什么叫事件委托呢?它还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件.那这是什么意思呢?网上的各位 ...
- C#事件与委托详解
from https://www.cnblogs.com/sjqq/p/6917497.html C#事件与委托详解[精华 多看看] Delegatedelegate是C#中的一种类型,它实际上是一个 ...
- 委托与事件代码详解与(Object sender,EventArgs e)详解
委托与事件代码详解 using System;using System.Collections.Generic;using System.Text; namespace @Delegate //自定义 ...
- jQuery.ready() 函数详解
jQuery.ready() 函数详解 ready()函数用于在当前文档结构载入完毕后立即执行指定的函数. 该函数的作用相当于window.onload事件. 你可以多次调用该函数,从而绑定多个函数, ...
- cocos2dx+lua注册事件函数详解 事件
coocs2dx 版本 3.1.1 registerScriptTouchHandler 注册触屏事件 registerScriptTapHandler ...
- jQuery的观察者模式详解 转载
jQuery的观察者模式详解 投稿:hebedich 本文主要是介绍了jQuery中on方法及trigger方法,以及围绕这个方法来体验的观察者模式,是篇非常不错的文章,对我们理解观察者模式很有帮助. ...
- jquery的css详解(二)
jq的工具方法style用于设置样式,jq的实例方法css在设置样式时就是调用的它,接下来分析一下源码. jQuery.extend({ ............................ st ...
随机推荐
- Vue非父子组件传值
<template> <div id="app"> <v-home></v-home> <br> <hr> ...
- 使用SoapUI发送Post请求
https://www.cnblogs.com/xiaowangzi1110/p/8544264.html 使用SoapUI发送Post请求 SoapUI作为一个开源的工具,其具备强大的功能.易用的界 ...
- 004-行为型-11-解析器模式(Interpreter)
一.概述 提供了评估语言的语法或表达式的方式.这种模式实现了一个表达式接口,该接口解释一个特定的上下文.这种模式被用在 SQL 解析.符号处理引擎等. 意图:给定一个语言,定义它的文法表示,并定义一个 ...
- Spring cloud微服务安全实战-5-2前端页面改造
创建一个新的maveb项目,做一个admin的管理界面 用angular写前面的页面. 先吧dependcency引用引进来. 前端的插件能帮我在springboot里面搭建出一个nodeJS的环境来 ...
- 【440】Tweet 元素意义
参考:Tweet Object 参考:Geo Objects 参考:User Object Ref: Place data dictionary Tweet Object Attribut ...
- DEBUG技巧1 SE37将参数保存为测试数据
1. SE37调试函数的时候,将参数保存为测试数据,供下次调试使用, 或者参考标准的赋值进行赋值 2. SE37 ->执行-> 测试序列 测试函数: CO_XT_COMPONENTS_DE ...
- Python - Django - ORM 多对多操作
models.py: from django.db import models # 出版社 class Publisher(models.Model): id = models.AutoField(p ...
- Uncaught TypeError: TableInit is not a constructor
我最近在做东西的时候,用到了Bootstrap的表格,我复制了一份代码使用,结果运行报错 Uncaught TypeError: TableInit is not a constructor 我点进去 ...
- vscode springboot logback 日志输出到不同文件
参照了:https://blog.csdn.net/appleyk/article/details/78717388# 在src\main\resources中新建一个logback-boot.xml ...
- Django 之memcached的应用
memcached介绍: memcached之前是danga的一个项目,最早是为LiveJournal服务的,当初设计师为了加速LiveJournal访问速度而开发的,后来被很多大型项目采用.官网是w ...