1. js事件模型
当我们点击页面上的一个元素时,浏览器是如何捕获并处理事件的。针对这个,js中有一个事件流的概念。当一个事件发生时会产生一个事件流,可通过event.eventPhase来获取当前处于哪个阶段。event.eventPhase的值与事件流阶段的对应关系如下:
值 |
描述 |
0 |
当前没有事件被处理 |
1 |
捕获阶段:从window开始,从上至下传播,直到到达目标的父元素。 |
2 |
目标阶段:事件已到达目标target |
3 |
冒泡阶段:事件从目标target的父元素开始,从下到上传播,最终到达window。 |
针对这几个阶段,提供了相关demo进行演示:点击进入
特别说明:ie低版本只支持冒泡
2. e.target与e.currentTarget的区别
属性 |
描述 |
e.target |
触发事件的目标元素,即你点击了一个按钮,此时target就是那个按钮 |
e.currentTarget |
事件流当前所处阶段到达的元素。 |
这两个的区别demo演示,同上。
3. preventDefault与stopPropagation
preventDefault:阻止元素针对所触发事件的默认行为;
stopPropagation:阻止事件冒泡;
4. 什么是dispatchEvent
手动触发事件。demo 参考资料
5. 事件代理的实现
类似于jquery的事件代理,原理就是利用事件流的冒泡阶段:把事件绑定在祖先元素A上,然后在事件处理器中,从e.target开始寻找,直至A结束(不包括A),看期间有没有某个元素是待监听的元素,如果是,则触发相应的处理事件。
简单事件代理demo
6. 事件代理的问题
如果同时给span与li绑定事件该如何阻止冒泡???
这个的话,在上述第5条的例子中,我就已经给出了演示,调用e.stopPropagation()阻止冒泡就可以了。比如给span的处理事件中调用e.stopPropagation()
7. tap事件是如何实现的
tap,只指在移动设备,我们触发的一个“点击”事件。虽然有touchend和click,但直接监听这2个事件都有问题:
touchend:触摸动作结束,但是直接监听touchend会有一个常见的问题。比如我们给一个列表ul的li绑定touchend事件,但是此时用户在ul里向上滑动,想看剩下的列表项内容,会触发li的touchend事件,造成bug;
click:移动设备为了判断用户是单击,还是双击,还是其他动作。touchend后到触发click会有一个300ms的延时,这样子会造成页面反应迟钝。
tap事件,就是为了解决300ms延时。用户要绑定一个元素的点击事件,可以使用如Zepto里面的tap事件。
tap事件实现:
1. touchstart时,通过e.touches获取当前的触摸点,并记录起始坐标点pageX、pageY、 目标元素target及其他相关信息
2. touchmove时,记录触摸点移动的新坐标pageX、pageY,并和在touchstart里记录的起始坐标点算移动差值deltaX、deltaY;
3. touchend时,结合之前记录的各种数据,判断用户的操作手势swipe,tap,singleTap,doubleTap,来触发相应事件。不过值得说明的是,tap包含singleTap和doubleTap,其中singleTap会比tap有250ms的延时。
zepto的touch.js源码
8. tap会产生什么问题
zepto的tap事件,产生一个很明显的问题就是“点透”
“点透”现象具体如下:
这个明显是个bug
分析:body是包含“蓝色块”的(即在DOM树上)在它冒泡到body之前,用户手的接触屏幕和离开屏幕是会先触发click事件的,(根据click事件的规则,只有在被触发时,当前有click事件的元素显示,且在面朝用户的最前端时,才触发click事件)由于click延迟,此时上面的“红色块”已经隐藏,满足下面的“蓝色块”的click事件的触发条件,于是click事件就被触发了,即“点透”了。
代码原因:其实就是因为zepto.touch.js,给body绑定touchend的时候,没有阻止默认事件。调用e.preventDefault()则可以阻止默认的click
document.body.addEventListener('touchend',function(e){
e.preventDefault();
});
这样子,点击红色块,不会触发蓝色块的click事件了。不过这个不是最好的方案,因为这样就阻止了页面上元素监听click事件了。
9. zepto的touch库做了什么?
给body绑定touchstart,touchmove,touchend事件,根据e.touches来获取触摸点,然后判断用户手势。具体说明请参见 第7点
10. fastclick解决了什么问题
解决了click事件的300ms延时,也解决了zepto tap的点透。
请先查看fastclick官方说明
fastclick的实现方式和zepto.touch.js大同小异,但是有几点很重要的区分:
1. 可以任意指定需要绑定fastclick的元素,不会默认绑定在body上;
2. 在待绑定的元素上,监听touchend,阻止默认事件(即阻止了浏览器默认的click),手动触发目标元素的click事件(dispatchEvent)
11. 实现一个滑动touch库
简单实现一个在移动设备下,监听swipe手势的touch库,并识别up,down,left,right四个方向。
滑动touch