-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
谁说你只是"会用"jQuery? #3
Comments
哈喽,谦龙,.on可以为没有不存在的dom元素绑定事件。是如何做到的呢。多谢您 |
@qianlongo 正是您说的第二种例子呢。这种机制是如何实现的呢? |
@lidazhao 为你点赞。 对于刚才那种情况,我们创建了存在于内存中但是没有塞入网页的元素,用.on给他添加事件,其实和有没有塞入网页没有太大的关系,可以认为就是给网页中的元素添加事件。而手动触发就是trigger的原理了。 但是还有另外一种情况比如
addNoElementEvent() 这种就有点类似于你刚才的解释了,不是触发事件,而是直接触发回调函数。 |
@qianlongo 哦,我懂了。我之前看你的评论我还是有些迷糊,最近很忙没看,今天睡觉有个东西触发了我想了下,再看您写的。我豁然开朗。感谢您。 |
@lidazhao 👍 一起学习 |
This was referenced Oct 1, 2017
Open
Open
Open
Open
Open
This was referenced Apr 29, 2018
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
前言
前端在最近几年实在火爆异常,vue、react、angular各路框架层出不穷,咱们要是不知道个双向数据绑定,不晓得啥是虚拟DOM,也许就被鄙视了。火热的背后往往也是无尽的浮躁,学习这些先进流行的类库或者框架可以让我们走的更快,但是静下心来回归基础,把基石打牢固,却可以让我们走的更稳,更远。
最近一直在看zepto的源码,希望通过学习它掌握一些框架设计的技巧,也将很久不再拾起的js基础重新温习巩固一遍。如果你对这个系列感兴趣,欢迎点击
watch
,随时关注动态。这篇文章主要想说一下zepto中事件模块(event.js)的添加事件on
以及移除事件off
实现原理,中间会详细地讲解涉及到的细节方面。如果你想看event.js全文翻译版本,请点击这里查看
原文地址
仓库地址
说在前面
但是用了这么久的zepto你知道这样写代码
是怎么实现事件委托的吗?为啥此时的
this
就是你点中的li
呢?平常我们可能还会这样写。
写法有点多,也许你还有其他的写法,那么
on
bind
delegate
live
click()
这些添加事件的形式,有什么区别,内部之间又有什么联系呢?
相信你在面试过程中也遇到过类似的问题(
看完这边文章,你可以知道答案的噢😯
)?接下来我们从源码的角度一步步去探究其内部实现的原理。
一切从
on
开始祭出一张画了好久的图
上面大概是zepto中
on
形式注册事件的大致流程,好啦开始看源码啦,首先是on函数,它主要做的事情是注册事件前的参数处理,真正添加事件是内部函数add。直接看到这么一大坨的代码不易于理解,我们分段进行阅读。
第一段
这段代码主要是为了处理下面这种调用形式。
这种写法我们平时写的比较少一点,但是确实是支持的。而zepto的处理方式则是循环调用
on
方法,以key
为事件名,val
为事件处理函数。在开始第二段代码阅读前,我们先回顾一下,平时经常使用
on
来注册事件的写法一般有哪些还会有其他的写法,但是常见的可能就是这些,第二段代码就是处理这些参数以让后续的事件正确添加。
第二段
三个if语句很好的处理了多种使用情况的参数处理。也许直接看不能知晓到底是如何做到的,可以试试每种使用情况都代入其中,找寻其是如何兼容的。
接下来我们第三段
这段函数做了非常重要的两件事
我们一件件看它如何实现。
内部用了一个
remove
函数,这里先不做解析,只要知道他就是移除事件的函数就可以,当移除事件的时候,再执行了传进来的回调函数。进而实现只调用一次的效果。那么事件代理又是怎么实现咧?
回想一下平常自己是怎么写事件代理的,一般是利用事件冒泡(当然也可以使用事件捕获)的性质,将子元素的事件委托到祖先元素身上,不仅可以实现事件的动态性,还可以减少事件总数,提高性能。
举个例子
我们把原本要添加到li上的事件委托到父元素ul上。
点击查看效果
回到第三段
zepto中实现事件代理的基本原理是:以当前目标元素
e.target
为起点向上查找到最先符合selector
选择器规则的元素,然后扩展了事件对象,添加了一些属性,最后以找到的match元素作为回调函数的内部this
作用域,并将扩展的事件对象作为回调函数的第一个参数传进去执行。这里需要知道
.closest(...)
api的具体使用,如果你不太熟悉,请点击这里查看说道这里,事件还没有添加啊!到底在哪里添加的呢,on函数的最后一句,便是要进入事件添加了。
参数处理完,开始真正的给元素添加事件了
我的神,又是这么长长长长的一大坨,人艰不拆,看着心累啊啊啊啊!!!
不过不用急,只要一步步去看,最终肯定可以看懂的。
开头有一句话
zepto中会给添加事件的元素身上加一个唯一的标志,_zid从1开始不断往上递增。后面的事件移除函数都是基于这个id来和元素建立关联的。
handlers
便是事件缓冲池,以数字0, 1, 2, 3...保存着一个个元素的事件处理程序。来看看handlers长啥样。html
javascript
以上截图便是这段代码执行后得到的handlers,其本身是个对象,每个key(1, 2, 3 ...)(这个key也是和元素身上的_zid属性一一对应的)都保存着一个数组,而数组中的每一项目都保存着一个与事件类型相关的对象。我们来看看,每个key的数组都长啥样
这样的设置给后面事件的移除带了很大的便利。画个简单的图,看看元素添加的事件和handlers中的映射关系。
明白了他们之间的映射关系,我们再回到源码处,继续看。
暂时去除了一些内部代码逻辑,我们看到其对
event
做了切分,并循环添加事件,这也是我们像下面这样添加事件的原因那么接下来我们要关注的就是循环的内部细节了。添加了部分注释
至此,添加事件到这里告一段落了。让我们再回到文章初始的问题,
on
bind
delegate
live
click()
这些添加事件的形式,有什么区别,内部之间又有什么联系呢?其实看他们的源码大概就知道区别
bind和click()函数都是直接将事件绑定到元素身上,live则代理到body元素身上,delegate是小范围是事件代理,性能在由于live,on就最厉害了,以上函数都可以用on实现调用。
事件移除的具体实现
同样先放一张事件移除的大致流程图
off函数
off函数基本上和on函数是一个套路,先做一些基本的参数解析,然后把移除事件的具体工作交给remove函数实现,所以我们主要看remove函数。
remove函数
继续往下走,一个重要的函数findHandlers
因为注册事件的时候回调函数不是用户传入的fn,而是自定义之后的proxy函数,所以需要将用户此时传入的fn和handler中保存的fn相比较是否相等。
结尾
如果对你有一点点帮助,点击这里,加一个小星星好不好呀
如果对你有一点点帮助,点击这里,加一个小星星好不好呀
如果对你有一点点帮助,点击这里,加一个小星星好不好呀
The text was updated successfully, but these errors were encountered: