读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 相关文章推荐
不用MOUSEMOVE也能滑动啊
May 23 Javascript
jQuery验证Checkbox是否选中的代码 推荐
Sep 04 Javascript
《JavaScript高级程序设计》阅读笔记(三) ECMAScript中的引用类型
Feb 27 Javascript
javascript中RegExp保留小数点后几位数的方法分享
Aug 13 Javascript
JavaScript创建一个object对象并操作对象属性的用法
Mar 23 Javascript
几种二级联动案例(jQuery\Array\Ajax php)
Aug 13 Javascript
JS转换HTML转义符的方法
Aug 24 Javascript
JavaScript 值类型和引用类型的初次研究(推荐)
Jul 19 Javascript
详解vue-admin和后端(flask)分离结合的例子
Feb 12 Javascript
vue-cli下的vuex的简单Demo图解(实现加1减1操作)
Feb 26 Javascript
Vue框架下引入ActiveX控件的问题解决
Mar 25 Javascript
JS设置自定义快捷键并实现图片上下左右移动
Oct 17 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命名空间namespace的定义方法详解
2017/03/29 PHP
Laravel5.5 动态切换多语言的操作方式
2019/10/25 PHP
Javascript实例教程(19) 使用HoTMetal(3)
2006/12/23 Javascript
Prototype使用指南之range.js
2007/01/10 Javascript
Jquery 扩展方法
2010/05/06 Javascript
jQuery EasyUI API 中文文档 搜索框
2011/09/29 Javascript
js弹出层之1:JQuery.Boxy (二)
2011/10/06 Javascript
javascript制作坦克大战全纪录(1)
2014/11/27 Javascript
浅谈nodeName,nodeValue,nodeType,typeof 的区别
2015/01/13 Javascript
JavaScript实现Java中StringBuffer的方法
2015/02/09 Javascript
Node.js 条形码识别程序构建思路详解
2016/02/14 Javascript
angularjs 源码解析之injector
2016/08/22 Javascript
vuejs响应用户事件(如点击事件)
2017/03/14 Javascript
JS中将多个逗号替换为一个逗号的实现代码
2017/06/23 Javascript
温故知新——JavaScript中的字符串连接问题最全总结(推荐)
2017/08/21 Javascript
vue获取元素宽、高、距离左边距离,右,上距离等还有XY坐标轴的方法
2018/09/05 Javascript
JQuery常见节点操作实例分析
2019/05/15 jQuery
js实现时钟定时器
2020/03/26 Javascript
vue脚手架项目创建步骤详解
2021/03/02 Vue.js
[51:29]Alliance vs TNC 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/18 DOTA
Python中顺序表的实现简单代码分享
2018/01/09 Python
python实现windows下文件备份脚本
2018/05/27 Python
Python 一句话生成字母表的方法
2019/01/02 Python
python3实现指定目录下文件sha256及文件大小统计
2019/02/25 Python
Python字符串大小写转换拼接删除空白
2019/09/19 Python
python drf各类组件的用法和作用
2021/01/12 Python
python基于Kivy写一个图形桌面时钟程序
2021/01/28 Python
Html5新增标签有哪些
2017/04/13 HTML / CSS
路由表示做什么用的?在linux环境中怎么来配置一条默认路由?
2013/06/07 面试题
给同学的道歉信
2014/01/16 职场文书
优秀党员获奖感言
2014/02/18 职场文书
测控技术自荐信
2014/06/05 职场文书
上海世博会志愿者口号
2014/06/17 职场文书
承诺书模板
2014/08/30 职场文书
升学宴演讲稿
2014/09/01 职场文书
2014年教学工作总结
2014/11/13 职场文书