方法的源码分析如下:
remove: function( elem, types, handler, selector, mappedTypes ) { var j, handleObj, tmp, origCount, t, events, special, handlers, type, namespaces, origType, //获取该元素的jQuery内部数据 elemData = jQuery.hasData( elem ) && jQuery._data( elem ); //如果内部数据不存在,或者内部数据没有events域那么直接返回! if ( !elemData || !(events = elemData.events) ) { return; } //可以传入一个通过空格分隔的事件类型 // Once for each type.namespace in types; type may be omitted types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; //对所有的事件类型进行遍历 while ( t-- ) { //rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; //如打印[click.test,click,test] tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); //如果teypes不存在,那么移除所有的事件!也就是当前元素的events域中间的所有的数据! // Unbind all events (on this namespace, if provided) for the element if ( !type ) { //type是空,那么直接移除events下面所有的事件! for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } //获取该类型事件的special进行特殊处理 special = jQuery.event.special[ type ] || {}; //如果存在selector那么就是代理对象,否则就是绑定事件到elem上面! type = ( selector ? special.delegateType : special.bindType ) || type; //获取回调函数集合 handlers = events[ type ] || []; //创建该命名空间下的一个正则表达式 tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); // Remove matching events origCount = j = handlers.length; while ( j-- ) { //获取该类型事件的所有的handleObj事件 handleObj = handlers[ j ]; //判断该对象的origType,如果和handleObj一样表示该类事件全部要移除!但是必须移除的对象是origType,guid,namespace,selector都相同才可以! if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !tmp || tmp.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { //splice接受两个参数,第一个参数表示开始的位置,第二个表示删除的个数! handlers.splice( j, 1 ); //如果是selector存在表示代理对象,那么把delegateCount递减! if ( handleObj.selector ) { handlers.delegateCount--; } //如果special有remove方法,那么直接调用special的remove方法! if ( special.remove ) { special.remove.call( elem, handleObj ); } } } // Remove generic event handler if we removed something and no more handlers exist // (avoids potential for endless recursion during removal of special event handlers) //如果当前事件的回调函数集合已经为空,同时该speical没有tearDown或者tearDown是false,那么用removeEvent方法! if ( origCount && !handlers.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } //移除当前回调函数集合! delete events[ type ]; } } //如果events对象已经是空了,那么直接连handle也移除,因为events不存在那么handle已经没有存在的意义了! //所以移除handle同时连events域也同时移除! // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { delete elemData.handle; // removeData also checks for emptiness and clears the expando if empty // so use it instead of delete jQuery._removeData( elem, "events" ); } }
如果传入的off("")是空字符串,那么会把所有的事件都移除,见下例:
$("#input").on("click",function(){alert("invoke1")}); $("#input").on("mouseover",function(){alert("invoke2")}); $("#input").off("");//所有的事件都会被移除!remove方法逻辑:
(1)获取Element上所有的内部数据
(2)获取要移除的types事件类型集合,并且循环移除某一类事件如click=types[i]
(3)如果传入的参数types[i]不存在事件类型,那么移除events域下面的所有的事件。但是如果传入remove("test")时候types[i]也是存在的,只有remove("")才是移除所有的事件
(4)如果传入的types[i]事件类型存在,那么获取events域中该类事件所有的函数句柄,并移出handles相对回调函数,并且把delegate自减!
注意:要移除相应的事件必须是origType,namespace,guid,selector都相等才可以!mappedTypes用于当用户没有传入要移除的事件类型的时候如传入空字符串时候用!