zepto 事件分析3(add函数)
在上一篇的分析中,最后$.on方法返回了一个add方法函数的执行,在这里先看一下其代码:
function add(element, events, fn, data, selector, delegator, capture){
var id = zid(element), set = (handlers[id] || (handlers[id] = []))
events.split(/\s/).forEach(function(event){
if (event == 'ready') return $(document).ready(fn)
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){
var related = e.relatedTarget
if (!related || (related !== this && !$.contains(this, related)))
return handler.fn.apply(this, arguments)
}
handler.del = delegator
var callback = delegator || fn
handler.proxy = function(e){
e = compatible(e)
if (e.isImmediatePropagationStopped()) return
e.data = data
var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args))
if (result === false) e.preventDefault(), e.stopPropagation()
return result
}
handler.i = set.length
set.push(handler)
if ('addEventListener' in element)
element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
})
}
在这里先跳过id以及handler部分(handler.e的值即为事件的type属性),该函数主要作用就是将事件添加进元素的事件队列里。
首先是对events进行分割成多个事件,并通过each函数逐个绑定。先来看一下函数里面的条件判定:
hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
if (handler.e in hover) fn = function(e){
var related = e.relatedTarget
if (!related || (related !== this && !$.contains(this, related)))
return handler.fn.apply(this, arguments)
}
如果事件的type属性是mouseenter或者mouseleave,那么需要重新定义绑定函数fn,什么是relatedTarget呢?
relatedTarget 属性用于在一个事件中查找另外一个元素。有些事件比如 mouseover 通常侧重处理一个特定的目标,而有些有也可能会涉及到第二目标,比如当目标退出第一目标的 mouseover 事件.

获得relatedTarget元素后,zepto对其进行判断,if (!related || (related !== this && !$.contains(this, related))),假设我们有两个div。
<div class="out">
<div class="in"></div>
</div>
我们对div.out定义mouseenter事件后,当我们鼠标从div.in移出来,但鼠标仍然在div.out,那么鼠标自始至终都在div.out中,但还是触发了mouseenter事件,这可能与预期中不同,所以zepto在这里加了判断,如果relatedTarget元素不存在,或者relatedTarget元素不是我们想要触发的元素本身,并且不包含在其中,即返回一个调用原来的fn函数。
接下来就是handler.proxy函数了,该函数的作用就是通过apply调用绑定的事件函数,并返回结果。
最后通过原生addEvent来绑定函数。
最后,总结一下zepto中绑定事件的思路:
1.找到目标元素。 即match = $(e.target).closest(selector, element).get(0),如果没有selector即跳过。
2.事件委托。如果存在selector,即重新生成一个事件,并通过compitable,createProxy对其进行修改,并改变其currentTarget属性,如果不存在selector,即对要绑定的dom执行compitable,添加eventMethod中的方法。
3.事件绑定,当存在selector触发时,实际触发的是$对象中的dom元素,只是通过事件委托使得像在符合selector条件元素中执行一样。
ps:当存在selector时,假设绑定了click事件,但点击的是$对象中的dom元素并且区域不在selector中,同样触发了事件对象,只是上一篇中的delegator函数里,如果找不到selector,那么跳过,不执行我们绑定的函数。$中的dom元素绑定的是handler.proxy函数,handler.proxy返回的是delegator的执行结果,而delegator如果找不到selector,那么就不执行我们绑定的函数。
zepto 事件分析3(add函数)的更多相关文章
- zepto 事件分析2($.on)
这里主要分析zepto事件中的$.on函数,先看一下该函数的代码 $.fn.on = function(event, selector, data, callback, one){ var autoR ...
- zepto 事件分析4(事件队列)
前面分析了zepto的事件绑定,接下来分析事件解绑,先看一下zepto中解绑的off方法: $.fn.off = function(event, selector, callback){ var $t ...
- zepto 事件分析1($.Event)
先看一下zepto事件的函数,在这里,zepto是把zepto对象作为一个立即执行函数的参数传进去的. (function($){ ... ... })(Zepto) 在zepto事件函数中,主要为$ ...
- Zepto事件模块源码分析
Zepto事件模块源码分析 一.保存事件数据的handlers 我们知道js原生api中要移除事件,需要传入绑定时的回调函数.而Zepto则可以不传入回调函数,直接移除对应类型的所有事件.原因就在于Z ...
- jQuery源码解读-事件分析
最原始的事件注册 addEventListener方法大家应该都很熟悉,它是Html元素注册事件最原始的方法.先看下addEventListener方法签名: element.addEventList ...
- 移动web app开发必备 - zepto事件问题
问题描述: 项目在祖先元素上绑定了 touchstart,touchmove,touchend事件,用来处理全局性的事件,比如滑动翻页 正常状态下: 用户在子元素上有交互动作时,默认状态下都是会冒泡到 ...
- 源码分析MySQL mysql_real_query函数
目录 目录 1 1. 前言 1 2. 调用路径 2 3. MAX_PACKET_LENGTH宏 2 4. DBUG_RETURN宏 3 5. COM_QUERY枚举值 3 6. mysql_query ...
- Zepto源代码分析一~核心方法
今天抽出时间复习了一下Zepto的源代码,依照自己的理解进行凝视. 欢迎大家拍砖. 源代码版本号:v1.1.4 源代码下载地址:http://zeptojs.com/ 分析总体代码之后,整理出架构图: ...
- Zepto源代码分析之二~三个API
因为时间关系:本次仅仅对这三个API($.camelCase.$.contains.$.each)方法进行分析 第一个方法变量转驼峰:$.camelCase('hello-world-welcome' ...
随机推荐
- 计算机网络六:无线局域网、IEEE 802.11、WIFI和蓝牙
无线局域网.IEEE 802.11.WIFI和蓝牙 ㈠无线局域网 1.定义 无线局域网络(Wireless Local Area Networks),简称WLAN.它是相当便利的数据传输系 ...
- C++的IO处理中的头文件以及类理解(2)<sstream>头文件
C++的IO处理中的头文件以及类理解(2)<sstream>头文件 头文件<sstream>中定义的类型都继承iostream头文件中定义的类型.除了继承得来的操作,sstre ...
- FPGA中带优先级的if else if与不带优先级的case的探讨
我们知道在书本上都说让我们尽量使用不带优先级的的数据选择器,今天我们就来探讨一下二者的区别. 例子1:带优先级的的数据选择器,综合成功,且没有任何警告. module detection_prio # ...
- 设置npm的registry
.原npm地址 npm config set registry http://registry.npmjs.org .设置国内镜像 a.通过config命令 npm config set regist ...
- Oracle数据库用EF操作的示例
Using EF Oracle Sample Provider with EDM Designer (from msdn) Many people are asking if it is possi ...
- Android 视频播放器 (一):使用VideoView播放视频
一.简介 作为Android开发,我们不可避免的会接触到视频播放,VideoView做为最简单的播放器,我们是不应该不会的. 下面简单介绍一下VideoView: VideoView是使用MediaP ...
- 第85节:Java中的JavaScript
第85节:Java中的JavaScript 复习一下css: 选择器的格式: 元素选择器:元素的名称{} 类选择器:. 开头 ID选择器:# ID选择器 后代选择器: 选择器1 选择器2 子元素选择器 ...
- 关键字New,如阴魂不散
本文是溪源翻译的第一篇技术文章,查看原文,因时间仓促,也许翻译过程措辞不当,还请见谅. 当你使用类似于C#或VisualBasic这种强类型语言,在实例化对象时,你往往会使用New这个关键字.我敢保证 ...
- JavaScript状态模式及状态机模型
这是一篇,我自己都看不完的文章... 文章大体就两部分: 状态模式的介绍 状态机模型的函数库javascript-state-machine的用法和源码解析 场景及问题背景: 我们平时开发时本质上就是 ...
- Go语言之Interface(二)
使用指针接收器和值接收器实现接口 type Describer interface { Describe() } type Person struct { name string age int } ...