Heim  >  Fragen und Antworten  >  Hauptteil

javascript – Problem beim Ein- und Ausschalten von jQuery-Ereignisbindungen

Der Code lautet wie folgt:

var $test = $(document);
  
function handler1() {
  console.log( "handler1" );
  $test.off( "click", handler2 );
}
  
function handler2() {
  console.log( "handler2" );
}
  
$test.on( "click", handler1 );
$test.on( "click", handler2 );

Warum gibt dieser Code Handler1 und Handler2 aus, wenn er zum ersten Mal angeklickt wird? Das Aus in Handler1 funktioniert, aber Handler2 wird trotzdem einmal ausgeführt.
Siehe jQuery-Dokumentation

Die Erklärung im Dokument lautet: Das Hinzufügen oder Entfernen von Ereignishandlern für das aktuelle Element wird erst wirksam, wenn das Ereignis das nächste Mal behandelt wird.
Vielleicht ist mein Englisch zu schlecht, ich habe das Gefühl, dass der Ausdruck an dieser Stelle nicht sehr genau ist , es sollte sein Das Hinzufügen oder Löschen desselben Ereignisses ist während der aktuellen Verarbeitung ungültig. Ich habe beispielsweise die beiden Klicks wie folgt geändert

var $test = $(document);
  
function handler1() {
  console.log( "handler1" );
  $test.off( "mouseup", handler2 );
}
  
function handler2() {
  console.log( "handler2" );
}
  
$test.on( "mousedown", handler1 );
$test.on( "mouseup", handler2 );

Dann wird nur Handler1 ausgegeben. Es ist ersichtlich, dass das Ausschalten von Mouseup in Mousedown erfolgreich ist

Zurück zum Anfang: Warum ist das Hinzufügen oder Löschen desselben Ereignisses während der aktuellen Verarbeitung ungültig? (Ich habe versucht, den Quellcode von jQuery zu finden, aber es war ziemlich kompliziert, also habe ich aufgegeben)

迷茫迷茫2684 Tage vor496

Antworte allen(3)Ich werde antworten

  • ringa_lee

    ringa_lee2017-05-18 10:53:00

    还是得从源码开始讲解

    先看这里: https://github.com/jquery/jqu...

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

    此处为事件分发的核心代码开始处,可见jquery分发事件时需调用 this.event.handler 求出事件回调的列表,此处 handlerQueue 只是内部事件列表一部分的拷贝,而你用 off 改变的是内部事件列表,对拷贝出的 handlerQueue 自然没有影响。

    就像是全部的事件回调函数都存在锅里,当有事件发生时,jquery 会把一部回调拷贝,盛到碗里,然后依次执行碗里的函数。你 off 改变的仅是锅里的函数,碗里的不受影响。

    Antwort
    0
  • ringa_lee

    ringa_lee2017-05-18 10:53:00

    可以把on可以看成把处理方法加到组件的一个事件处理数组里,off就是从数组里去掉这个方法。当事件触发时,jq就会一次执行事件处理数组里的方法,那么如果事件处理方法里调用了off会怎么样?文档里已经写的很清楚了,在当前事件触发循环里并不会立刻从数组里去掉该处理方法,只有当绑定的事件再触发时才会体现。

    Antwort
    0
  • 天蓬老师

    天蓬老师2017-05-18 10:53:00

    感谢大家
    问题找到了,原因在于jq内部对于事件的封装处理时,同一类型的事件会添加到同一个数组中,而在触发事件时遍历又是这个数组的一个复制,off没有改变复制的数组,所以导致第一次click的时候输出了hanler2,而对于mousedown和mouseup,因为是不同类型的事件,是封装成两个数组的,所以在mousedown中off掉mouseup是有效的。也许表达的不是很好,贴几行主要的jq源码

    //获取触发的事件的数组,在上面的代码中触发click时这个数组中是有两个值的,而触发mousedown时是只有一个值的,这个值是内部封装的一个handleObj对象
    handlers = ((jQuery._data(this, "events") || {})[event.type] || [])
    
    ...
    
    //之后会把这个handlers数组根据是否委托来slice(也是这个地方复制了handlers,导致click中的off第一次点击的时候无效),然后添加到数组handlerQueue中
    handlerQueue.push({ elem: this, matches: handlers.slice(delegateCount) })
    
    ...
    //最后触发的时候是遍历handlerQueue中的matches来执行
     for (i = 0; i < handlerQueue.length && !event.isPropagationStopped() ; i++) {
                    matched = handlerQueue[i];
                    event.currentTarget = matched.elem;
    
                    for (j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped() ; j++) {
                        ...
                        }
    }

    Antwort
    0
  • StornierenAntwort