javascript - Wie implementiert jQuery off(), um Ereignisse zu entfernen?
高洛峰
高洛峰 2017-06-12 09:27:06
0
2
1125

Wir wissen, dass jede Methode zum Binden eines Ereignisses in jQuery ihre entsprechende Methode zum Entfernen der Ereignisbindung hat. Beispielsweise entspricht off() on(), unbind() entspricht bind() und die() entspricht live (). Ich bin sehr neugierig, wie diese Art der Entbündelung anonymer Ereignisse implementiert wird. Der Quellcode von jQuery ist zu esoterisch und schwer zu verstehen. Kann ein Experte eine vereinfachte Version des Codes veröffentlichen, um das Implementierungsprinzip zu analysieren?

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

Antworte allen(2)
phpcn_u1582

我觉得要理解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方法。

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参数还传了特定的回调函数,那么则是对回调数组遍历比对,删除对应的回调函数……

对于jquery源码这块,前期基础部分推荐看 妙味课堂 的视频, 其他可以看 http://www.cnblogs.com/aaronj... 大牛博文,或者购置jquery源码解析类似书籍。

源码涉及的细节太多, 一时半会我也整理不出来= =,我就把大致观点表述一下……有啥理解错误请指正~

phpcn_u1582

以下是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 );
    } );
}
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!