读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 相关文章推荐
silverlight线程与基于事件驱动javascript引擎(实现轨迹回放功能)
Aug 09 Javascript
jquery中的事件处理详细介绍
Jun 24 Javascript
jQuery修改li下的样式以及li下的img的src的值的方法
Nov 02 Javascript
PHP+jQuery+Ajax+Mysql如何实现发表心情功能
Aug 06 Javascript
JavaScript的Backbone.js框架的一些使用建议整理
Feb 14 Javascript
jQuery插件FusionCharts实现的2D柱状图效果示例【附demo源码下载】
Mar 06 Javascript
requirejs按需加载angularjs文件实例
Jun 08 Javascript
JavaScript解析任意形式的json树型结构展示
Jul 23 Javascript
vue实现计步器功能
Nov 01 Javascript
vue实现图片上传预览功能
Dec 23 Javascript
openlayers实现图标拖动获取坐标
Sep 25 Javascript
Vue自定义铃声提示音组件的实现
Jan 22 Vue.js
仅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
PHP5.3.1 不再支持ISAPI
2010/01/08 PHP
微信公众号实现会员卡领取功能
2017/06/08 PHP
JSON 客户端和服务器端的格式转换
2009/08/27 Javascript
LazyForm jQuery plugin 定制您的CheckBox Radio和Select
2009/10/24 Javascript
jquery 根据name名获取元素的value值
2015/02/27 Javascript
jquery衣服颜色选取插件效果代码分享
2015/08/28 Javascript
ionic实现滑动的三种方式
2016/08/27 Javascript
JQuery实现列表中复选框全选反选功能封装(推荐)
2016/11/24 Javascript
jQuery实现动态生成表格并为行绑定单击变色动作的方法
2017/04/17 jQuery
JavaScript数据结构与算法之队列原理与用法实例详解
2017/11/22 Javascript
详解vue-cli脚手架中webpack配置方法
2018/08/22 Javascript
小程序获取当前位置加搜索附近热门小区及商区的方法
2019/04/08 Javascript
微信小程序如何再次获取用户授权的方法
2019/05/10 Javascript
vue Cli 环境删除与重装教程 - 版本文档
2020/09/11 Javascript
[01:10:02]IG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
采用python实现简单QQ单用户机器人的方法
2014/07/03 Python
使用python开发vim插件及心得分享
2014/11/04 Python
Python使用matplotlib实现的图像读取、切割裁剪功能示例
2018/04/28 Python
TensorFlow 模型载入方法汇总(小结)
2018/06/19 Python
Python实现查询某个目录下修改时间最新的文件示例
2018/08/29 Python
对python3 中方法各种参数和返回值详解
2018/12/15 Python
Pyinstaller 打包exe教程及问题解决
2019/08/16 Python
如何解决django-celery启动后迅速关闭
2019/10/16 Python
Django配置文件代码说明
2019/12/04 Python
基于python实现操作redis及消息队列
2020/08/27 Python
详解Python中的Lock和Rlock
2021/01/26 Python
html5本地存储_动力节点Java学院整理
2017/07/12 HTML / CSS
中国海淘族值得信赖的海淘返利网站:55海淘
2017/01/16 全球购物
小学生开学第一课活动方案
2014/03/27 职场文书
学校四群教育实施方案
2014/06/12 职场文书
企业法人授权委托书范本
2014/09/23 职场文书
2014年组织委员工作总结
2014/12/01 职场文书
上课睡觉万能检讨书
2015/02/17 职场文书
2015年效能监察工作总结
2015/04/23 职场文书
2015年教师节主持词
2015/07/03 职场文书
mysql 索引的数据结构为什么要采用B+树
2022/04/26 MySQL