读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 相关文章推荐
国外Lightbox v2.03.3 最新版 下载
Oct 17 Javascript
JS自动缩小超出大小的图片
Oct 12 Javascript
ajax与302响应代码测试
Oct 23 Javascript
JSON+HTML实现国家省市联动选择效果
May 18 Javascript
js实现鼠标滚轮控制图片缩放效果的方法
Feb 20 Javascript
Javascript基础_简单比较undefined和null 值
Jun 14 Javascript
jQuery+Ajax请求本地数据加载商品列表页并跳转详情页的实现方法
Jul 12 jQuery
node-sass安装失败的原因与解决方法
Sep 04 Javascript
分享ES6的7个实用技巧
Jan 18 Javascript
微信小程序获取用户openid的实现
Dec 24 Javascript
JS实现带阴历的日历功能详解
Jan 24 Javascript
vue created钩子函数与mounted钩子函数的用法区别
Nov 05 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
PHPMyadmin 配置文件详解(配置)
2009/12/03 PHP
php实现的仿阿里巴巴实现同类产品翻页
2009/12/11 PHP
ThinkPHP3.1.3版本新特性概述
2014/06/19 PHP
PHP mysql事务问题实例分析
2016/01/18 PHP
PHP转换文本框内容为HTML格式的方法
2016/07/20 PHP
PHP笛卡尔积实现算法示例
2018/07/30 PHP
javascript判断iphone/android手机横竖屏模式的函数
2011/12/20 Javascript
Javascript让DEDECMS告别手写Tag
2014/09/01 Javascript
60个很实用的jQuery代码开发技巧收集
2014/12/15 Javascript
JS根据生日算年龄的方法
2015/05/05 Javascript
JavaScript实现iframe自动高度调整和不同主域名跨域
2016/02/27 Javascript
用AngularJS的指令实现tabs切换效果
2016/08/31 Javascript
JS实现多级菜单中当前菜单不随页面跳转样式而发生变化
2017/05/30 Javascript
React组件之间的通信的实例代码
2017/06/27 Javascript
JS实现table表格内针对某列内容进行即时搜索筛选功能
2018/05/11 Javascript
boostrap模态框二次弹出清空原有内容的方法
2018/08/10 Javascript
对vue下点击事件传参和不传参的区别详解
2018/09/15 Javascript
老生常谈JavaScript获取CSS样式的方法(兼容各浏览器)
2018/09/19 Javascript
在vue中嵌入外部网站的实现
2020/11/13 Javascript
[01:14]TI珍贵瞬间系列(六):冠军
2020/08/30 DOTA
Python开发常用的一些开源Package分享
2015/02/14 Python
Python导入txt数据到mysql的方法
2015/04/08 Python
用python写扫雷游戏实例代码分享
2018/05/27 Python
python requests post多层字典的方法
2018/12/27 Python
对python3 sort sorted 函数的应用详解
2019/06/27 Python
Python爬虫实现模拟点击动态页面
2020/03/05 Python
为你的html5网页添加音效示例
2014/04/03 HTML / CSS
关于HTML5+ API plusready的兼容问题
2020/11/20 HTML / CSS
罗马尼亚购物网站:Vivantis.ro
2019/07/20 全球购物
介绍一下RMI的基本概念
2016/12/17 面试题
教师三严三实对照检查材料
2014/09/25 职场文书
2014年领班工作总结
2014/11/25 职场文书
2014年英语教研组工作总结
2014/12/06 职场文书
Python趣味爬虫之用Python实现智慧校园一键评教
2021/05/28 Python
用Python生成会跳舞的美女
2022/01/18 Python
Spring Data JPA框架的核心概念和Repository接口
2022/04/28 Java/Android