本篇来介绍下关于jQ解除事件的流程:
先来看下对外的api:
$().unbind(); $().undelegate(); $().off()
先来看下结构:
jQuery.fn.extend({
//...
off: function( types, selector, fn ) {
//...
return this.each(function() {
jQuery.event.remove( this, types, fn, selector );
});
},
unbind: function( types, fn ) {
return this.off( types, null, fn );
},
undelegate: function( selector, types, fn ) {
return arguments.length == 1?
this.off( selector, "**" ) :
this.off( types, selector, fn );
},
//...
});
和绑定事件类似,这里可以看出最终都会执行到 .off -> jQuery.event.remove
jQuery.fn.extend({
//...
//卸载事件
//types 可以是空格分开的多个事件类型,已分发的jQEvent对象,jsObj
//selector 用于移除事件代理
off: function( types, selector, fn ) {
//types.handleObj 存在则说明是被 jQuery.event.dispatch(event)分发的jQ事件对象
if ( types && types.preventDefault && types.handleObj ) {
var handleObj = types.handleObj;
//取出相应的参数,递归调用.off,移除当前正在执行的函数
jQuery( types.delegateTarget ).off(
handleObj.namespace ?
handleObj.origType + "." + handleObj.namespace :
handleObj.origType,
handleObj.selector,
handleObj.handler
);
return this;
}
if ( typeof types === "object" ) {
// { click: fn, mouseover: fn } 遍历循环调用
for ( var type in types ) {
this.off( type, selector, types[ type ] );
}
return this;
}
if ( selector === false || typeof selector === "function" ) {
// ( types fn )
fn = selector;
selector = undefined;
}
//如果传入的fn是false,则指向returnFalse函数
if ( fn === false ) {
fn = returnFalse;
}
//遍历dom对象,进行逐一调用
return this.each(function() {
jQuery.event.remove( this, types, fn, selector );
});
},
//...
}
jQuery.event = {
//...
//移除事件
remove: function( elem, types, handler, selector, mappedTypes ) {
// false || {}
var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
t, tns, type, origType, namespaces, origCount,
j, events, special, handle, eventType, handleObj;
//如果 数据缓存对象上没有events列表则直接返回即可
if ( !elemData || !(events = elemData.events) ) {
return;
}
//切割事件类型成数组,主要是针对hover事件
types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
for ( t = 0; t < types.length; t++ ) {
// 'click.namespace','click','namespace'
tns = rtypenamespace.exec( types[t] ) || [];
type = origType = tns[1];
namespaces = tns[2];
// 如果没指定事件类型,则遍历删除所有events内的东西
if ( !type ) {
for ( type in events ) {
// 这里进行一次拼接 是处理 .space 的情况: 删除指定空间下的所有事件
jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
}
continue;
}
//对某些事件类型进行修正
special = jQuery.event.special[ type ] || {};
//selector如果存在,则是想删除委托事件,如果有修正的话,这里使用修正的事件类型
type = ( selector ? special.delegateType : special.bindType ) || type;
//type类型监听的 事件队列 数组
eventType = events[ type ] || [];
origCount = eventType.length;
namespaces = namespaces ?
new RegExp("(^|\\.)" +
namespaces.split(".").sort().join("\\.(?:.*\\.)?") +
"(\\.|$)") :
null ;
for ( j = 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
if(
// mappedTypes 参数如果传入true,则不进行类型检测
( mappedTypes || origType === handleObj.origType ) &&
// 如果传入函数 则检测函数的id和函数进行guid的匹配检测
( !handler || handler.guid === handleObj.guid ) &&
// 如果指定了命名空间,则进行空间的检测
( !namespaces || namespaces.test( handleObj.namespace ) ) &&
// 如果传入了 选择器,检查和函数指定的selector是否相同,
// 或者传入 "**" 的话,则移除所有带selector的函数
( !selector ||
selector === handleObj.selector ||
selector === "**" && handleObj.selector )
){
// 将函数从数组中移除
// 移除的时候同时进行变量减一,以便每次正确的调用到数据中的每项
eventType.splice( j--, 1 );
// 如果是移除了selector,则维持下delegateCount变量
if ( handleObj.selector ) {
eventType.delegateCount--;
}
// 修正事件如果有 remove, 则调用下
if ( special.remove ) {
special.remove.call( elem, handleObj );
}
}
}
// 如果函数队列为空 && 以前队列是有函数的 的时候,则移除主监听函数
if ( eventType.length === 0 && origCount !== eventType.length ) {
// 在使用remove移除之前,如果有修正对象的teardown方法,则调用之,然后在使用移除
if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
jQuery.removeEvent( elem, type, elemData.handle );
}
//删除空了的属性 events: { 'click':[],'mouseover':[] }
delete events[ type ];
}
}
//如果 events 为空对象的时候,把 events 和 主监听函数 handle 从缓存中移除
if ( jQuery.isEmptyObject( events ) ) {
handle = elemData.handle;
if ( handle ) {
handle.elem = null;
}
jQuery.removeData( elem, [ "events", "handle" ], true );
}
},
//...
}
这两篇代码有点多哦,还有大约3篇关于"DOM事件"的...
本篇就介绍到这里,总结下:
通过很多形式开放的api方便用户的各种解除操作 ↓
处理各种情况的参数,整理完毕后调用统一的内部处理函数 ↓
各种检测数据合法性,然后删除对应的函数↓
返回this(jQ对象)
感谢您的阅读,欢迎留言:斧正,交流,提问;