首先基本的科普知识 .on() and .off()方法是jQuery1.7正式版发布
代码示例1
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 );
第一次点击document,会在控制台看到
handler1
handler2
代码示例2
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 );
第一次点击document,会在控制台看到
handler1
问题来了,为什么同一事件的添加或删除在当前处理过程中无效?
查看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++) {
...
}
}
原因在于jq内部对于事件的封装处理时,同一类型的事件会添加到同一个数组中,而在触发事件时遍历又是这个数组的一个复制,off没有改变复制的数组,所以导致第一次click的时候输出了hanler2,而对于mousedown和mouseup,因为是不同类型的事件,是封装成两个数组的,所以在mousedown中off掉mouseup是有效的。