程式碼如下:
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 );
這段程式碼為什麼第一次點擊的時候會輸出handler1和handler2,handler1中的off起作用了但是仍然會執行一次handler2,原因是什麼?
參考jQuery文件
文檔裡解釋的是: Adding or removing event handlers on the current element won't take effect until the next time the event is handled
也許是我英語太渣,我感覺這個地方表述的不是很準確,應該是同一事件的新增或刪除在目前處理過程中無效,例如我把兩個click改成如下
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 );
那就只會輸出handler1,可見在mousedownoff掉mouseup是成功的
回到最開始,為什麼同一事件的新增或刪除在目前處理過程中無效? (我試著找了找jQuery的源碼,比較複雜,放棄了)
還是得從源碼開始講解
先看這裡: https://github.com/jquery/jqu...
此處為事件分發的核心代碼開始處,可見jquery分發事件時需調用this.event.handler 求出事件回調的列表,此處handlerQueue 只是內部事件列表一部分的拷貝,而你用off 更改的是內部事件列表,對拷貝出的handlerQueue 自然沒有影響。
就像是全部的事件回呼函數都存在鍋裡,當有事件發生時,jquery 會把一部回調拷貝,盛到碗裡,然後依次執行碗裡的函數。你 off 改變的只是鍋子裡的函數,碗裡的不受影響。
可以把on可以看成把處理方法加到組件的一個事件處理數組裡,off就是從數組裡去掉這個方法。當事件觸發時,jq就會一次執行事件處理數組裡的方法,那麼如果事件處理方法裡呼叫了off會怎麼樣?文件裡已經寫的很清楚了,在當前事件觸發循環裡並不會立刻從數組裡去掉該處理方法,只有當綁定的事件再觸發時才會體現。
感謝大家
問題找到了,原因在於jq內部對於事件的封裝處理時,同一類型的事件會添加到同一個數組中,而在觸發事件時遍歷又是這個數組的一個複製,off沒有改變複製的數組,所以導致第一次click的時候輸出了hanler2,而對於mousedown和mouseup,因為是不同類型的事件,是封裝成兩個數組的,所以在mousedown中off掉mouseup是有效的。也許表達的不是很好,貼幾行主要的jq源碼