读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 相关文章推荐
层序遍历在ExtJs的TreePanel中的应用
Oct 16 Javascript
根据选择不同的下拉值出现相对应的文本输入框
Aug 01 Javascript
js获取url参数值的两种方式
Sep 10 Javascript
Javascript中的delete操作符详细介绍
Jun 06 Javascript
学习JavaScript设计模式之中介者模式
Jan 14 Javascript
JSON字符串和JSON对象相互转化实例详解
Jan 05 Javascript
AngularJS中的路由使用及实现代码
Oct 09 Javascript
微信小程序返回多级页面的实现方法
Oct 27 Javascript
解决使用Vue.js显示数据的时,页面闪现原始代码的问题
Feb 11 Javascript
详解JavaScript原生封装ajax请求和Jquery中的ajax请求
Feb 14 jQuery
Vue左滑组件slider使用详解
Aug 21 Javascript
Ant Design Pro 之 ProTable使用操作
Oct 31 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
2020年4月放送决定!第2期TV动画《邪神酱飞踢》视觉图&主题曲情报公开!
2020/03/06 日漫
第四节--构造函数和析构函数
2006/11/16 PHP
如何突破PHP程序员的技术瓶颈分析
2011/07/17 PHP
php实现singleton()单例模式实例
2014/11/06 PHP
php的socket编程详解
2016/11/20 PHP
PHP基于双向链表与排序操作实现的会员排名功能示例
2017/12/26 PHP
javascript下操作css的float属性的特殊写法
2007/08/22 Javascript
jQuery 页面载入进度条实现代码
2009/02/08 Javascript
DOM_window对象属性之--clipboardData对象操作代码
2011/02/03 Javascript
使用jquery插件实现图片延迟加载技术详细说明
2011/03/12 Javascript
javascript实现链接单选效果的方法
2015/05/13 Javascript
JavaScript保存并运算页面中数字类型变量的写法
2015/07/06 Javascript
javascript动态生成树形菜单的方法
2015/11/14 Javascript
利用AJAX实现WordPress中的文章列表及评论的分页功能
2016/05/17 Javascript
深入浅析Vue不同场景下组件间的数据交流
2017/08/15 Javascript
基于react组件之间的参数传递(详解)
2017/09/05 Javascript
修改node.js默认的npm安装目录实例
2018/05/15 Javascript
微信小程序实现保存图片到相册功能
2018/11/30 Javascript
微信小程序的线程架构【推荐】
2019/05/14 Javascript
js实现图片推拉门效果代码实例
2019/05/18 Javascript
vue scroll滚动判断的实现(是否滚动到底部、滚动方向、滚动节流、获取滚动区域dom元素)
2020/06/11 Javascript
vue-amap根据地址回显地图并mark的操作
2020/11/03 Javascript
Ubuntu16.04/树莓派Python3+opencv配置教程(分享)
2018/04/02 Python
python 顺时针打印矩阵的超简洁代码
2018/11/14 Python
Python实现随机创建电话号码的方法示例
2018/12/07 Python
python类中super() 的使用解析
2019/12/19 Python
Python-numpy实现灰度图像的分块和合并方式
2020/01/09 Python
浅谈css3新单位vw、vh、vmin、vmax的使用详解
2017/12/01 HTML / CSS
法国房车租赁网站:Yescapa
2019/08/26 全球购物
成人大专生实习期的自我评价
2013/10/02 职场文书
优秀教师获奖感言
2014/01/31 职场文书
会计学自我鉴定
2014/02/06 职场文书
市场营销专业求职信
2014/06/17 职场文书
家长评语怎么写
2014/12/30 职场文书
2015年消防工作总结
2015/04/24 职场文书
保安辞职申请书应该怎么写?
2019/07/15 职场文书