读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 相关文章推荐
javascript实现可改变滚动方向的无缝滚动实例
Jun 17 Javascript
Jquery动态改变图片IMG的src地址示例
Jun 25 Javascript
jquery设置按钮停顿3秒不可用
Mar 07 Javascript
基于canvas实现的钟摆效果完整实例
Jan 26 Javascript
jQuery实现点击行选中或取消CheckBox的方法
Aug 01 Javascript
BootStrap组件之进度条的基本用法
Jan 19 Javascript
vue组件实现文字居中对齐的方法
Aug 23 Javascript
AngularJS中scope的绑定策略实例分析
Oct 30 Javascript
node.js实现为PDF添加水印的示例代码
Dec 05 Javascript
webpack4 从零学习常用配置(小结)
May 28 Javascript
axios如何利用promise无痛刷新token的实现方法
Aug 27 Javascript
在 Vue 中使用 JSX 及使用它的原因浅析
Feb 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
PHP获取网址的顶级域名函数代码
2012/09/24 PHP
基于php上传图片重命名的6种解决方法的详细介绍
2013/04/28 PHP
Thinkphp模板标签if和eq的区别和比较实例分析
2015/07/01 PHP
php正则提取html图片(img)src地址与任意属性的方法
2017/02/08 PHP
PDO::inTransaction讲解
2019/01/28 PHP
JavaScript数组各种常见用法实例分析
2015/08/04 Javascript
javascript验证手机号和实现星号(*)代替实例
2016/08/16 Javascript
Jquery根据浏览器窗口改变调整大小的方法
2017/02/07 Javascript
jQuery实现导航回弹效果
2017/02/27 Javascript
javaScript 逻辑运算符使用技巧整理
2017/05/03 Javascript
JavaScript实现计算多边形质心的方法示例
2018/01/31 Javascript
Vue项目History模式404问题解决方法
2018/10/31 Javascript
vue实现可视化可拖放的自定义表单的示例代码
2019/03/20 Javascript
Vue项目总结之webpack常规打包优化方案
2019/06/06 Javascript
实现一个 Vue 吸顶锚点组件方法
2019/07/10 Javascript
小程序如何在不同设备上自适应生成海报的实现方法
2019/08/20 Javascript
在vue中实现echarts随窗体变化
2020/07/27 Javascript
python黑魔法之参数传递
2016/02/12 Python
Python 递归函数详解及实例
2016/12/27 Python
pyqt5简介及安装方法介绍
2018/01/31 Python
对python中的乘法dot和对应分量相乘multiply详解
2018/11/14 Python
对python中list的拷贝与numpy的array的拷贝详解
2019/01/29 Python
Python对wav文件的重采样实例
2020/02/25 Python
详解HTML5中div和section以及article的区别
2015/07/14 HTML / CSS
英国排名第一的礼品体验公司:Red Letter Days
2018/08/16 全球购物
党校个人自我鉴定范文
2014/03/28 职场文书
预备党员公开承诺书
2014/05/28 职场文书
体育教育毕业生自荐信
2014/06/29 职场文书
村级四风对照检查材料
2014/08/24 职场文书
2015毕业寄语大全
2015/02/26 职场文书
作弊检讨书范文
2015/05/06 职场文书
婚礼答谢词范文
2015/09/29 职场文书
python实现网络五子棋
2021/04/11 Python
Python之基础函数案例详解
2021/08/30 Python
讲解MySQL增删改操作
2022/05/06 MySQL
Python Matplotlib绘制动画的代码详解
2022/05/30 Python