84669 人学习
152542 人学习
20005 人学习
5487 人学习
7821 人学习
359900 人学习
3350 人学习
180660 人学习
48569 人学习
18603 人学习
40936 人学习
1549 人学习
1183 人学习
32909 人学习
我们知道jQuery每个绑定事件的方法都有其对应的移除事件绑定的方法,例如off()对应on(),unbind()对应bind(),die()对应live(),很好奇这种对匿名事件的解绑是怎么实现的,jQuery的源码太深奥又看不太懂,哪位大神能贴上简化版的代码解析下实现原理吗?
拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...
我觉得要理解off处理,得先理解on的操作,去年读过jquery2.x的源码,事件这块挺复杂的。
翻看了一下自己粗糙的笔记,关于事件这块当时讲解视频没有提及自己硬着头皮看的。
关于绑定事件可以结合on源码实现以及jquery.event.add方法:
我的理解是 jquery主要对元素设置缓存数据cache,cache存储了events变量 (事件回调队列集合),以“事件”:“回调函数数组”的形式存储,用以实现多次给某个dom添加事件时,回调都能触发,而实际真正用原生事件绑定的是对这个回调函数数组的遍历执行。
而对于off,先看看off的源码部分:
off: function( types, selector, fn ) { var handleObj, type; if ( types && types.preventDefault && types.handleObj ) { // ( event ) dispatched jQuery.Event handleObj = types.handleObj; jQuery( types.delegateTarget ).off( handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler ); return this; } if ( typeof types === "object" ) { // ( types-object [, selector] ) for ( type in types ) { this.off( type, selector, types[ type ] ); } return this; } if ( selector === false || typeof selector === "function" ) { // ( types [, fn] ) fn = selector; selector = undefined; } if ( fn === false ) { fn = returnFalse; } return this.each(function() { jQuery.event.remove( this, types, fn, selector ); }); },
看到最后 一句,就知道,实际它调用了jQuery.event.remove方法。
jQuery.event.remove
remove方法
remove: function( elem, types, handler, selector, mappedTypes ) { var j, origCount, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = data_priv.hasData( elem ) && data_priv.get( elem ); if ( !elemData || !(events = elemData.events) ) { return; } // Once for each type.namespace in types; type may be omitted types = ( types || "" ).match( core_rnotwhite ) || [""]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); // Unbind all events (on this namespace, if provided) for the element if ( !type ) { for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } special = jQuery.event.special[ type ] || {}; 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 = handlers[ j ]; if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !tmp || tmp.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { handlers.splice( j, 1 ); if ( handleObj.selector ) { handlers.delegateCount--; } 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) if ( origCount && !handlers.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { delete elemData.handle; data_priv.remove( elem, "events" ); } },
主要是对元素获取前面on时存放在cache的events变量对事件键值对进行删除等操作。
如果只是$(xx).off('click'),那么就是直接遍历把events里click事件对应的回调函数组都给删了,如果off参数还传了特定的回调函数,那么则是对回调数组遍历比对,删除对应的回调函数……
$(xx).off('click')
对于jquery源码这块,前期基础部分推荐看 妙味课堂 的视频, 其他可以看 http://www.cnblogs.com/aaronj... 大牛博文,或者购置jquery源码解析类似书籍。
源码涉及的细节太多, 一时半会我也整理不出来= =,我就把大致观点表述一下……有啥理解错误请指正~
以下是on的代码
function on( elem, types, selector, data, fn, one ) { var origFn, type; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } for ( type in types ) { on( elem, type, selector, data, types[ type ], one ); } return elem; } if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return elem; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return elem.each( function() { jQuery.event.add( this, types, fn, data, selector ); } ); }
我觉得要理解off处理,得先理解on的操作,去年读过jquery2.x的源码,事件这块挺复杂的。
翻看了一下自己粗糙的笔记,关于事件这块当时讲解视频没有提及自己硬着头皮看的。
关于绑定事件可以结合on源码实现以及jquery.event.add方法:
我的理解是 jquery主要对元素设置缓存数据cache,cache存储了events变量 (事件回调队列集合),以“事件”:“回调函数数组”的形式存储,用以实现多次给某个dom添加事件时,回调都能触发,而实际真正用原生事件绑定的是对这个回调函数数组的遍历执行。
而对于off,先看看off的源码部分:
看到最后 一句,就知道,实际它调用了
jQuery.event.remove
方法。remove方法
主要是对元素获取前面on时存放在cache的events变量对事件键值对进行删除等操作。
如果只是
$(xx).off('click')
,那么就是直接遍历把events里click事件对应的回调函数组都给删了,如果off参数还传了特定的回调函数,那么则是对回调数组遍历比对,删除对应的回调函数……对于jquery源码这块,前期基础部分推荐看 妙味课堂 的视频, 其他可以看 http://www.cnblogs.com/aaronj... 大牛博文,或者购置jquery源码解析类似书籍。
源码涉及的细节太多, 一时半会我也整理不出来= =,我就把大致观点表述一下……有啥理解错误请指正~
以下是on的代码