我在理解$(“ button”)。click()和$(“ button”)[0] .click()的不同行为时遇到问题

时间:2019-06-24 05:20:53

标签: javascript jquery

当我尝试学习jquery时,我了解到$(selector)返回的对象具有该选择器的所有匹配项,并且像数组一样可迭代。例如,$("button")将返回一个对象,该对象可以访问 DOM 的所有按钮标签,以便访问第一个按钮标签,您可以第二次使用$["button"][0]使用$["button"][1],依此类推。

所以下面的代码集中在注释的第1行和第2行。

   <body>
        <button>Click me</button>
        <script>
            $(document).ready(function() {
// line 1
               $("button").click(function() {
                    console.log("1");
// line 2
                    $("button").click(); 
                });
            });
        </script>
    </body>

第1行的事件处理函数中的第2行设置了一个无限循环,如您所见,当我单击“单击我”按钮时,它将触发第1行,其中第2行也将触发第1行,依此类推。 现在,请参阅下面的代码片段,其中第2行已更改。

        <script>
            $(document).ready(function() {
// line 1
               $("button").click(function() {
                    console.log("1");
// line 2
                    $("button")[0].click();
                });
            });
        </script>

这一次不是设置无限循环,而是为什么两次打印到控制台“ 1”?

4 个答案:

答案 0 :(得分:6)

很可能是JQuery调用综合事件的方式。

这是用于事件分发的JQuery代码段。

dispatch: function( nativeEvent ) {

        // Make a writable jQuery.Event from the native event object
        var event = jQuery.event.fix( nativeEvent );

        var i, j, ret, matched, handleObj, handlerQueue,
            args = new Array( arguments.length ),
            handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
            special = jQuery.event.special[ event.type ] || {};

        // Use the fix-ed jQuery.Event rather than the (read-only) native event
        args[ 0 ] = event;

        for ( i = 1; i < arguments.length; i++ ) {
            args[ i ] = arguments[ i ];
        }

        event.delegateTarget = this;

        // Call the preDispatch hook for the mapped type, and let it bail if desired
        if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
            return;
        }

        // Determine handlers
        handlerQueue = jQuery.event.handlers.call( this, event, handlers );

        // Run delegates first; they may want to stop propagation beneath us
        i = 0;
        while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
            event.currentTarget = matched.elem;

            j = 0;
            while ( ( handleObj = matched.handlers[ j++ ] ) &&
                !event.isImmediatePropagationStopped() ) {

                // If the event is namespaced, then each handler is only invoked if it is
                // specially universal or its namespaces are a superset of the event's.
                if ( !event.rnamespace || handleObj.namespace === false ||
                    event.rnamespace.test( handleObj.namespace ) ) {

                    event.handleObj = handleObj;
                    event.data = handleObj.data;

                    ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
                        handleObj.handler ).apply( matched.elem, args );

                    if ( ret !== undefined ) {
                        if ( ( event.result = ret ) === false ) {
                            event.preventDefault();
                            event.stopPropagation();
                        }
                    }
                }
            }
        }

        // Call the postDispatch hook for the mapped type
        if ( special.postDispatch ) {
            special.postDispatch.call( this, event );
        }

        return event.result;
    }

读取spec上的合成和真实点击事件:

  

当用户代理要在元素上运行单击后激活步骤时,它必须运行为该元素定义的激活行为(如果有)。激活行为可以指的是到目前为止导致上述步骤触发的点击事件。

由于JQuery实现了用于模拟点击事件的自定义分派处理程序,因此它们似乎添加了以下内容来模拟上述的本机html事件生命周期。

if ( special.postDispatch ) {
   special.postDispatch.call( this, event );
}

在您查看以下控制台输出时,此处的调用很可能是可疑的。请注意,您永远不会看到console.log完成,因为调度处理程序实际上从不返回事件来完成其本机生命周期(无限递归),我怀疑本机html实现可以更好地处理该事件。

无限循环警告

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<body>
        <button>Click me</button>
        <script>
            $(document).ready(function() {
// line 1
               $("button").click(function() {
                    console.log("start");
// line 2
                    $("button").click(); 
                    console.log("Done");
                });
            });
        </script>
    </body>

好发现!

答案 1 :(得分:1)

当您执行$(“ button”)[0]时,您将获得不是jQuery对象的基础本机HTMLButtonElement对象。

答案 2 :(得分:0)

$('button').click(fn)做下面的事情

    $("button").each(function() {
        //this === native button htmlElement.
        if (!this._event) this._event = {};
        if (!this._event.click) this._event.click = [];
        this._event.click.push(fn);
        if (!this.clickHandler) {
            this.clickHandler = e => {
                this._event.click.forEach(f => f.bind(this)(e));
            };
            this.addEventListener("click", this.clickHandler);
        }
    });

$('button').click()表示

    $("button").each(function() {
        //this === native button htmlElement.
        if(this.clickHandler)this.clickHandler();
        if(typeof this.onclick === 'function') this.onclick();
    });

这只是一个例子,jquery事件的源代码要复杂得多。

为什么$("button")[0].click()只打印'1'两次? 原生click模拟了鼠标在按钮元素上的点击,因此出于安全原因,我认为该循环已被Explorer阻止。

bind events source code

trigger source code

答案 3 :(得分:0)

$(“ button”)返回一个jq对象,它调用jq对象上的方法,而$(“ button”)[0]返回一个DOM对象,它调用dom本机方法