复制代码 代码如下:
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事件管理的数据结构,我做了个图。如下
