前面分析了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))
})
})
}

function findHandlers(element, event, fn, selector) {
    event = parse(event)
    if (event.ns) var matcher = matcherFor(event.ns)
    return (handlers[zid(element)] || []).filter(function(handler) {
      return handler
      && (!event.e || handler.e == event.e)
      && (!event.ns || matcher.test(handler.ns))
      && (!fn || zid(handler.fn) === zid(fn))
      && (!selector || handler.sel == selector)
    })
}

 

首先通过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解绑,并返回绑定事件的执行。这样就保证了只执行一次。

最新文章

  1. 设计模式(五): 简单而又不失其重要性的单例模式(Singleton Pattern)
  2. js学习进阶中-bind()方法
  3. zend studio(Eclipse)和PyDev搭建Python开发环境
  4. libxml2 移植 arm9
  5. 更改PATH后,别忘了及时重启或刷新
  6. 【模拟】ECNA 2015 I What's on the Grille? (Codeforces GYM 100825)
  7. DayOfWeek中英文星期转换
  8. Ajax框架,DWR介绍,应用,样例
  9. Sort list by merge sort
  10. C++ CRTP singleton
  11. shift、unshift、 push、pop用法--JavaScript参考手册
  12. 201521123006 《Java程序设计》 第2周学习总结
  13. Maven 学习总结 (二) 之 生命周期与插件
  14. HTML与CSS的一些知识(四)
  15. 表格中的checkbox复选框 全选非全选 公共方法 及提交选中结果
  16. 深入浅出JAVA线程池使用原理2
  17. Linux基础命令---ifcfg
  18. sql zhuan ORACLE
  19. hdu 4282 枚举,非二分
  20. JavaScript模块化思想之入门篇

热门文章

  1. 登陆页、注册页、会员中心页logo图的替换
  2. 启动eclipse could not create the java Vittual Machine
  3. BZOJ4720-换教室
  4. Apache启动不成功时,用命令行检测(新手)
  5. mysql case when then else end 的写法
  6. 吴恩达机器学习笔记4-代价函数III(cost function)
  7. OAuth2.0认证详解
  8. 全栈开发工程师微信小程序-中(下)
  9. java实操之使用jcraft进行sftp上传下载文件
  10. Python制作二维码和条形码扫描器 (pyzbar)