У меня проблемы с пониманием различного поведения $ ("кнопка"). Click() и $ ("кнопка") [0].click()

Пока я пытался изучить jquery, я узнал, что $ (селектор) возвращает объект, который имеет все совпадения этого селектора и является итеративным, как массивы. например, $("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>

Строка 2 внутри функции обработчика событий line1 настроена на бесконечный цикл, так как вы можете видеть, что когда я нажимаю кнопку "Нажми меня", она запускает строку 1, внутри которой находится строка 2, которая тоже снова запускает строку 1 и так далее. Теперь посмотрите приведенный ниже фрагмент кода с измененной строкой 2.

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

На этот раз он не устанавливает бесконечный цикл, а выводит на консоль "1" только два раза, почему так?

Ответы

Ответ 1

Скорее всего, 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;
    }

Чтение спецификации для синтетических и аутентичных событий кликов:

Когда пользовательский агент должен выполнить шаги активации после щелчка для элемента, он должен запустить поведение активации, определенное для этого элемента, если оно есть. Поведение активации может относиться к событию щелчка, которое было вызвано шагами выше, приведшими к этой точке.

Поскольку в 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>

Ответ 2

Когда вы делаете $ ("button") [0], вы получаете базовый нативный объект HTMLButtonElement, который не является объектом jQuery.

Ответ 3

$('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 имитирует щелчок мыши на элементе кнопки, поэтому я предполагаю, что цикл заблокирован Проводником по соображениям безопасности.

связать исходный код событий

триггерный исходный код

Ответ 4

$ ("button") возвращает объект jq, он вызывает методы объекта jq, а $ ("button") [0] возвращает объект DOM, он вызывает собственный метод dom

Ответ 5

Когда вы делаете $ ("button") [0].click(), он вызывает первый щелчок кнопки, и у нас есть первая кнопка в DOM, поэтому, когда она снова появится внутри функции, она будет искать кнопки, доступные в $ (" кнопка ") [0], которая не определена.

Например: если вы нажмете метод прямо из консоли, это будет как показано ниже So in the image if you see first time click is working and second time it is throwing undefined