读jQuery之十一 添加事件核心方法

这篇看看其源码,这个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事件管理的数据结构,我做了个图。如下

(0)

相关推荐

  • 读jQuery之七 判断点击了鼠标哪个键的代码

    jQuery丢弃了标准的 button 属性采用 which,这有点让人费解. which 是Firefox引入的,IE不支持.which的本意是获取键盘的键值(keyCode). jQuery中的which即可以是键盘的键值,也可以是鼠标的键值.即当判断用户按下键盘的哪个键时可以使用which,当判断用户按下鼠标的哪个键时也可以用which.它一举两用了.源码 复制代码 代码如下: // Add which for key events if ( event.which == null &&am

  • 读jQuery之十二 删除事件核心方法

    .remove 所作的事情与上一篇提到的.add 刚好相反.且与.add中的处理代码一一对应,即  .add 中有多少种添加事件的方式.remove就有对应的删除方式. .remove 定义了四个参数 elem, types, handler, pos .从字面上看四个参数的意义很明了 elem 为HTMLElement types 为String类型,事件名称如'click'或'mouseover mouseout' handler 为Function类型,事件回调函数 pos 为Number

  • 读jQuery之八 包装事件对象

    比如,停止事件冒泡IE用 cancelBubble ,标准浏览器则用 stopPropagation . 获取事件源对象,IE用 srcElement ,标准浏览器则用 target 诸如此类. jQuery 对原生事件对象的修复和包装主要使用 jQuery.Event 类和 jQuery.event.fix 方法. 复制代码 代码如下: jQuery.Event = function( src ) { // Allow instantiation without the 'new' keywo

  • 读jQuery之二(两种扩展)

    如下 复制代码 代码如下: jQuery.extend = jQuery.fn.extend = function() { ... }; 我们可以用$.extend去扩展自定义的对象,如 复制代码 代码如下: var myself = {name:jack}; $.extend(myself, {setName: function(n){this.name=n;} }); myself.setName("tom"); 通过$.extend为对象myself添加了setName方法.但这

  • 读jQuery之十 事件模块概述

    后面会详细分析jQuery.event.add/jQuery.event.remove/jQuery.event.trigger. 虽然事件模块代码很难读,但其提供的API接口还是很清晰的.如下 1 添加事件(bind/one/live/delegate/hover/toggle) bind 基本的添加事件函数. one 添加只执行一次的事件函数. live 事件代理(使用document代理). delegate 事件代理(使用指定元素代理). hover 模拟css的hover. toggl

  • 读jQuery之五(取DOM元素)

    jQuery的$调用后想要获取DOM元素可以使用get方法,如下 复制代码 代码如下: // 方式1 $('div').get(1); // 获取页面中第二个div 当然,也可以使用数组索引方式获取 复制代码 代码如下: // 方式2 $('div')[1]; // 获取页面中第二个div 上面两种方式都可以获取某一个特定的DOM元素,而获取DOM元素集合却要使用toArray方法 复制代码 代码如下: $('div').toArray(); // 返回页面中所有的div,依次放入数组中 看看g

  • 读jQuery之三(构建选择器)

    为了叙述每一篇的重点,其示例代码都是最精简的,比如选择器只能传HTMLElement和id. 这篇我们增强下选择器,依据2/8原则,这里仅实现最常用的几种. 1, 通过id获取,该元素是唯一的$('#id') 2, 通过className获取$('.cls') 获取文档中所有className为cls的元素$('.cls', el)$('.cls', '#id')$('span.cls') 获取文档中所有className为cls的span元素$('span.cls', el) 获取指定元素中c

  • 读jQuery之九 一些瑕疵说明

    1,bind 方法,最后一个参数fn是多余的 复制代码 代码如下: // Handle object literals if ( typeof type === "object" ) { for ( var key in type ) { this[ name ](key, data, type[key], fn); } return this; } 2,注释 复制代码 代码如下: // Add which for click: 1 === left; 2 === middle; 3

  • 读jQuery之六 缓存数据功能介绍

    很多同学在项目中都喜欢将数据存储在HTMLElement属性上,如 复制代码 代码如下: <div data="some data">Test</div> <script> div.getAttribute('data'); // some data </script> 给页面中div添加了自定义属性"data"及值"some data".后续JS代码中使用getAttribute获取. jQuer

  • 读jQuery之一(对象的组成)

    对于jQuery的写法甚是困惑,尤其在使用Prototype的$后,一度不能理解jQuery的$.对于现在前端同学来说,可能第一个接触的就是jQuery了,他们会觉得很习惯,很自然. 至今电脑里还存放着当时的API文档,发个图感叹下 在这段时间内,我的入门老师是墨墨,其实至今他仍然是我敬仰的同事之一.他的编程造诣很高,相信早已突破了编程语言的限制.在大家都在使用Prototype.js的时候,在jQuery尚未在国内流行的时候,他就已经把jQuery引入到项目中了. 言归正传吧,目前的jQuer

  • 读jQuery之四(优雅的迭代)

    jQuery的操作往往是分两步 1,获取元素集合(选择器) 2,操作元素集合 而第二步操作元素集合的主要方法就是jQuery.each.查看源码,我们发现jQuery.each及this.each分别调用了27次和31次.可见它是多么的重要. 这篇将分析下jQuery.each及this.each方法.看看他们如何与jQuery.extend一起扩展jQuery库.最后我会给zChain.js加上each方法. 部分源码如下 复制代码 代码如下: jQuery.fn = jQuery.proto

随机推荐