search

Home  >  Q&A  >  body text

javascript - How does jQuery implement off() to remove events?

We know that each method of binding events in jQuery has its corresponding method of removing event binding, such as off() corresponding to on(), unbind() corresponding to bind(), die() corresponding to live() , I am very curious about how this unbundling of anonymous events is achieved. The source code of jQuery is too esoteric and hard to understand. Can any expert post a simplified version of the code to analyze the implementation principle?

高洛峰高洛峰2795 days ago1313

reply all(2)I'll reply

  • phpcn_u1582

    phpcn_u15822017-06-12 09:29:06

    I think to understand off processing, you must first understand the on operation. I read the source code of jquery2.x last year, and the event aspect is quite complicated.

    I looked through my rough notes and found that the video explaining the incident did not mention anything about it that I had to watch.

    About binding events, you can combine the on source code implementation and the jquery.event.add method:

    My understanding is that jquery mainly sets cache data cache for elements. The cache stores events variables (event callback queue collection), which are stored in the form of "event": "callback function array" to add multiple times to a certain DOM. When an event occurs, the callback can be triggered, but what is actually bound to the native event is the traversal execution of the callback function array.

    As for off, let’s take a look at the source code part of off first:

    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 );
            });
        },

    When you see the last sentence, you know that it actually calls the jQuery.event.remove method.

    remove method

    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" );
            }
        },

    Mainly perform operations such as deleting event key-value pairs from the events variable stored in the cache when the element is previously on.

    If it is just $(xx).off('click'), then it is to directly traverse and delete the callback function group corresponding to the click event in events. If the off parameter also passes a specific callback function, then it is Traverse and compare the callback array and delete the corresponding callback function...

    For the jquery source code, it is recommended to watch the video of Miaowei Classroom for the early basic part. For other information, you can watch Daniel's blog post at http://www.cnblogs.com/aaronj... or purchase similar books on jquery source code analysis.

    The source code involves too many details, and I won’t be able to sort them out for a while = =, so I will express the general point... Please correct me if I have any misunderstandings~

    reply
    0
  • phpcn_u1582

    phpcn_u15822017-06-12 09:29:06

    The following is the code of 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 );
        } );
    }

    reply
    0
  • Cancelreply