读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 相关文章推荐
JQuery EasyUI 对话框的使用方法
Oct 24 Javascript
js获取指定日期周数以及星期几的小例子
Jun 27 Javascript
window.returnValue使用方法示例介绍
Jul 03 Javascript
Jquery实现由下向上展开效果的例子
Dec 08 Javascript
js中setTimeout()与clearTimeout()用法实例浅析
May 12 Javascript
js实现简易的单数字随机抽奖(0-9)
Mar 19 Javascript
js判断iframe中元素是否存在的实现代码
Dec 24 Javascript
使用bootstrap-paginator.js 分页来进行ajax 异步分页请求示例
Mar 09 Javascript
微信小程序自定义多列选择器使用详解
Jun 21 Javascript
package.json配置文件构成详解
Aug 27 Javascript
Vue-router 报错NavigationDuplicated的解决方法
Mar 31 Javascript
javascript实现前端分页功能
Nov 26 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通用分页类page.php[仿google分页]
2008/08/31 PHP
php目录管理函数小结
2008/09/10 PHP
浅析PHP微信支付通知的处理方式
2014/05/25 PHP
PHP判断IP并转跳到相应城市分站的方法
2015/03/25 PHP
PHP实现的统计数据功能详解
2016/12/06 PHP
PHPCrawl爬虫库实现抓取酷狗歌单的方法示例
2017/12/21 PHP
关于Laravel参数验证的一些疑与惑
2019/11/19 PHP
解决FLASH需要点击激活的代码
2006/12/20 Javascript
Jquery 基础学习笔记
2009/05/29 Javascript
ajax不执行success回调而是执行了error回调
2012/12/10 Javascript
一个简单的jQuery计算器实现了连续计算功能
2014/07/21 Javascript
JavaScript字符串对象substr方法入门实例(用于截取字符串)
2014/10/16 Javascript
谈谈我对JavaScript原型和闭包系列理解(随手笔记8)
2015/12/24 Javascript
python根据日期返回星期几的方法
2015/07/06 Python
详解python中xlrd包的安装与处理Excel表格
2016/12/16 Python
Django数据库操作的实例(增删改查)
2017/09/04 Python
使用pandas的DataFrame的plot方法绘制图像的实例
2018/05/24 Python
使用python实现ftp的文件读写方法
2019/07/02 Python
Python简易计算器制作方法代码详解
2019/10/31 Python
Python递归函数特点及原理解析
2020/03/04 Python
Python使用requests xpath 并开启多线程爬取西刺代理ip实例
2020/03/06 Python
Python Opencv 通过轨迹(跟踪)栏实现更改整张图像的背景颜色
2020/03/09 Python
html5 canvas 实现光线沿不规则路径运动
2020/04/20 HTML / CSS
加拿大领先的优质厨具产品在线购物网站:Golda’s Kitchen
2017/11/17 全球购物
ToysRus日本官网:玩具反斗城
2018/09/08 全球购物
德国拖鞋网站:German Slippers
2019/11/08 全球购物
C#公司笔试题
2014/03/28 面试题
个人简历自我评价范文
2014/02/04 职场文书
中职毕业生自我鉴定范文(3篇)
2014/09/28 职场文书
2014年司机工作总结
2014/11/21 职场文书
团代会邀请函
2015/02/02 职场文书
党委工作总结2015
2015/04/27 职场文书
医院党建工作总结2015
2015/05/26 职场文书
小英雄雨来观后感
2015/06/09 职场文书
创业计划书之溜冰场
2019/10/25 职场文书
Golang 正则匹配效率详解
2021/04/25 Golang