前面分析了zepto的事件绑定,接下来分析事件解绑,先看一下zepto中解绑的off方法:
$.fn.off = function(event, selector, callback){
var $this = this
if (event && !isString(event)) {
$.each(event, function(type, fn){
$this.off(type, selector, fn)
})
return $this
}
if (!isString(selector) && !isFunction(callback) && callback !== false)
callback = selector, selector = undefined
if (callback === false) callback = returnFalse
return $this.each(function(){
remove(this, event, callback, selector)
})
}
offf方法前面大致和on方法一样,最主要的是最后return里面的remove函数,在看remove之前,要先分析之前遇到的有关handler的函数,下面是在add方法中,关于handler的。
function add(element, events, fn, data, selector, delegator, capture){
var id = zid(element), set = (handlers[id] || (handlers[id] = []))
events.split(/\s/).forEach(function(event){
...
var handler = parse(event)
handler.fn = fn
handler.sel = selector
console.log(handler.e)
// emulate mouseenter, mouseleave
if (handler.e in hover) fn = function(e){
...
}
handler.del = delegator
var callback = delegator || fn
handler.proxy = function(e){
...
...
}
handler.i = set.length
set.push(handler)
if ('addEventListener' in element)
element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
})
}
首先通过zid函数设置一个id,并获得hanlders[id]数组,这里面使用了闭包的功能,在整个事件函数中定义了handlers和_zid两个变量,并在内部函数中采用函数的方式返回,使其不被回收。每个元素都有一个id,该id可以在handlers里面找到自己的事件队列。
var _zid = 1,handlers = {};
function zid(element) {
return element._zid || (element._zid = _zid++)
};
function add(...){
var id = zid(element), set = (handlers[id] || (handlers[id] = []));
...
};
$(".out").on('click',function(event) {
console.log($(this))
event.stopPropagation();
});
$(".in").on('click',function(event) {
console.log($(this))
});
接下来,add函数定义了一个handler变量。该变量通过将event作为参数传入parse函数获得。
function parse(event) {
var parts = ('' + event).split('.')
//返回一个对象,e为事件的type属性,ns为事件的命名空间
return {e: parts[0], ns: parts.slice(1).sort().join(' ')}
}
接下来,将事件的一系列相关参数放入handler里面,最后设置handler.i为set的长度(作为handler事件的一个index),并将handler放进set,也就是放进handlers[id]。
也就是说,像上面的例子定义之后,handlers里面是这样的(每一个属性代表一个元素里面的事件队列,如1是对应的数组是div.in的事件队列)。
分析handlers相关之后,就可以看remove函数了:
function remove(element, events, fn, selector, capture){
//获得元素在handlers中的对应id
var id = zid(element)
//遍历定义的事件
;(events || '').split(/\s/).forEach(function(event){
findHandlers(element, event, fn, selector).forEach(function(handler){
delete handlers[id][handler.i]
if ('removeEventListener' in element)
element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
})
})
}
首先通过finHandlers函数来查询符合的事件,该函数相对简单,通过filter来返回一个符合条件的事件数组,接下来通过delete语句删除handlers[id]中对应的handler,并使用原生的解绑事件解绑。
那么整个事件队列的分析就结束了,之前在分析$.on函数时,也有一个remove没有分析。
$.fn.on = function(event, selector, data, callback, one){
...
return $this.each(function(_, element){
if (one) autoRemove = function(e){
remove(element, e.type, callback)
return callback.apply(this, arguments)
}
...
add(element, event, callback, data, selector, delegator || autoRemove)
})
}
如果传入了one参数,那么就定义一个autoRemove函数,内部调用remove解绑,并返回绑定事件的执行。这样就保证了只执行一次。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有