读jQuery之十一 添加事件核心方法


Posted in Javascript onJuly 31, 2011

这篇看看其源码,这个add定义如下(省略大部分)

add: function( elem, types, handler, data ) { 
if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 
return; 
} 
... 
}

定义了四个参数elem、types、handler和data分别为HTMLElement、事件类型(如click)、事件响应函数、数据。此外,types 可以以空格分开传多种事件("mouseover mouseout")。handler 有时会是一个对象(实现live时)。data 最后会挂在扩充后的event对象上,即作为event的属性。而event会在handler作为第一个参数拿到,这样也就可以在handler拿到data了。
下面详细说明
if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 
return; 
}

文本和注释节点直接返回。
if ( handler === false ) { 
handler = returnFalse; 
} else if ( !handler ) { 
// Fixes bug #7229. Fix recommended by jdalton 
return; 
}

参数handler为false时,将handler赋值为returnFalse,returnFalse为一个函数,如下
function returnFalse() { 
return false; 
}

jQuery通过handler为false来阻止元素默认行为,停止事件冒泡。这个需要结合jQuery.event.handle看。
var handleObjIn, handleObj; 
if ( handler.handler ) { 
handleObjIn = handler; 
handler = handleObjIn.handler; 
} 
// Make sure that the function being executed has a unique ID 
if ( !handler.guid ) { 
handler.guid = jQuery.guid++; 
}

定义变量handleObjIn,handleObj。
handler从字面上看是事件响应(回调)函数,但这里出现handler.handler,让人倍感怪异。即什么时候会将handler当一个JS对象传入呢?
多数时候传的还是Function类型的,看看源码中jQuery.event.add的调用可发现jQuery在实现live的时候会传Object类型。如下
add: function( handleObj ) { 
jQuery.event.add( this, 
liveConvert( handleObj.origType, handleObj.selector ), 
jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); 
},

这时会把handleObjIn赋值为所传的JS对象,真正的handler 却是handleObjIn.handler。这话有点绕,慢慢体会。
// Make sure that the function being executed has a unique ID 
if ( !handler.guid ) { 
handler.guid = jQuery.guid++; 
}

所传参数handler添加个属性guid,为一个数字,自增的从1开始。即使用jQuery添加事件,会为事件响应函数默认的添加了属性guid。这个guid再删除事件时会用到。
// Init the element's event structure 
var elemData = jQuery._data( elem );

先取elemData,这里使用了前面提到的jQuery._data。第一次为HTMLElement添加事件是elemData是个空对象({})。
// If no elemData is found then we must be trying to bind to one of the 
// banned noData elements 
if ( !elemData ) { 
return; 
}

elemData不存在则直接返回。
var events = elemData.events, 
eventHandle = elemData.handle;

定义events,eventHandle。同样第一次时这两个变量都是undefined。
if ( !events ) { 
elemData.events = events = {}; 
} 
if ( !eventHandle ) { 
elemData.handle = eventHandle = function( e ) { 
// Discard the second event of a jQuery.event.trigger() and 
// when an event is called after a page has unloaded 
return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? 
jQuery.event.handle.apply( eventHandle.elem, arguments ) : 
undefined; 
}; 
}

给elemData.events和elemData.handle赋值。
// Add elem as a property of the handle function 
// This is to prevent a memory leak with non-native events in IE. 
eventHandle.elem = elem;

暂存elem到eventHandle,删除事件注册时会将其置null,避免部分浏览器中内存泄露。
// Handle multiple events separated by a space 
// jQuery(...).bind("mouseover mouseout", fn); 
types = types.split(" ");

将字符串以空格为切割符转成数组。这句使其可以一次添加多个事件,多个事件的handler是相同的。
后面是一个while循环
while ( (type = types[ i++ ]) ) { 
handleObj = handleObjIn ? 
jQuery.extend({}, handleObjIn) : 
{ handler: handler, data: data }; 
... 
}

循环数组,里面依次处理如下
, 取得handleObj
, 处理事件命名空间,以点号(.)来区别。如果type有点号,则具有命名空间,否则没有
, 给handlerObj添加type,guid属性。这些后续删除事件时用到
, 取到handlers,special。多数情况下使用addEventListener/attachEvent来添加事件。从变量special可看出对于特殊的事件如ready,beforeunload及live事件是特殊处理的。 ready 调用的是jQuery.bindReady,而jQuery.bindReady内部调用的仍然是 addEventListener/attachEvent。beforeunload则是使用window.onbeforeunload来添加。live是实现事件代理的,他的处理也是特殊的。
, 最后吧handleObj添加到数组handles中。
jQuery.event.add 的最后一句,解决IE中内存泄露。
// Nullify elem to prevent memory leaks in IE 
elem = null;

jQuery事件管理的数据结构,我做了个图。如下
读jQuery之十一 添加事件核心方法
Javascript 相关文章推荐
如何在Web页面上直接打开、编辑、创建Office文档
Mar 12 Javascript
javascript jQuery $.post $.ajax用法
Jul 09 Javascript
jQuery中$.fn的用法示例介绍
Nov 05 Javascript
JQuery中使用Ajax赋值给全局变量失败异常的解决方法
Aug 18 Javascript
JavaScript黑洞数字之运算路线查找算法(递归算法)实例
Jan 28 Javascript
JS正则表达式学习之贪婪和非贪婪模式实例总结
Dec 26 Javascript
js实现5秒倒计时重新发送短信功能
Feb 05 Javascript
jQuery实现鼠标响应式淘宝动画效果示例
Feb 13 jQuery
详解es6超好用的语法糖Decorator
Aug 01 Javascript
在 Angular6 中使用 HTTP 请求服务端数据的步骤详解
Aug 06 Javascript
Puppeteer 爬取动态生成的网页实战
Nov 14 Javascript
node后端服务保活的实现
Nov 10 Javascript
仅Firefox中链接A无法实现模拟点击以触发其默认行为
Jul 31 #Javascript
各浏览器对click方法的支持差异小结
Jul 31 #Javascript
js中将HTMLCollection/NodeList/伪数组转换成数组的代码
Jul 31 #Javascript
对象无length属性时IE6/IE7中无法将其转换成伪数组(ArrayLike)
Jul 31 #Javascript
javascript中length属性的探索
Jul 31 #Javascript
javascript string字符串优化问题
Jul 31 #Javascript
超级有用的13个基于jQuery的内容滚动插件和教程
Jul 31 #Javascript
You might like
Laravel中基于Artisan View扩展包创建及删除应用视图文件的方法
2016/10/08 PHP
PHP DB 数据库连接类定义与用法示例
2019/03/11 PHP
PHP设计模式之策略模式原理与用法实例分析
2019/04/04 PHP
js实现在字符串中提取数字
2013/11/05 Javascript
javascript生成随机大小写字母的方法
2014/02/20 Javascript
PHP中使用微秒计算脚本执行时间例子
2014/11/19 Javascript
完美兼容IE,chrome,ff的设为首页、加入收藏及保存到桌面js代码
2014/12/17 Javascript
JavaScript中调用函数的4种方式代码实例
2015/07/08 Javascript
javascript实现状态栏中文字动态显示的方法
2015/10/20 Javascript
jQuery语法小结(超实用)
2015/12/31 Javascript
详解Immutable及 React 中实践
2018/03/01 Javascript
vue实现点击展开点击收起效果
2018/04/27 Javascript
Vue实现购物车详情页面的方法
2019/08/20 Javascript
layui给下拉框、按钮状态、时间赋初始值的方法
2019/09/10 Javascript
微信小程序点击列表跳转到对应详情页过程解析
2019/09/26 Javascript
浅析微信小程序自定义日历组件及flex布局最后一行对齐问题
2020/10/29 Javascript
python+ffmpeg视频并发直播压力测试
2018/03/06 Python
pandas groupby 分组取每组的前几行记录方法
2018/04/20 Python
Python格式化输出字符串方法小结【%与format】
2018/10/29 Python
Pytorch 实现自定义参数层的例子
2019/08/17 Python
python使用pip安装模块出现ReadTimeoutError: HTTPSConnectionPool的解决方法
2019/10/04 Python
Python matplotlib以日期为x轴作图代码实例
2019/11/22 Python
python连接打印机实现打印文档、图片、pdf文件等功能
2020/02/07 Python
Python生成器实现简单"生产者消费者"模型代码实例
2020/03/27 Python
使用PyCharm安装pytest及requests的问题
2020/07/31 Python
Python脚本调试工具安装过程
2021/01/11 Python
美国顶级户外凉鞋品牌:Chacos
2017/03/27 全球购物
Crucial英睿达法国官网:内存条及SSD固态硬盘升级
2018/07/13 全球购物
函数只定义了一次, 调用了一次, 但编译器提示非法重定义了-什么问题?
2014/10/03 面试题
集团公司党的群众路线教育实践活动工作总结
2014/03/03 职场文书
团员个人年度总结
2015/02/26 职场文书
小学体育跳绳课教学反思
2016/02/16 职场文书
golang通过递归遍历生成树状结构的操作
2021/04/28 Golang
宝塔更新Python及Flask项目的部署
2022/04/11 Python
HTML CSS 一个标签实现带动画的抖音LOGO
2022/04/26 HTML / CSS
Python pyecharts案例超市4年数据可视化分析
2022/08/14 Python