【初窥javascript奥秘之事件机制】论“点透”与“鬼点击”
2013-11-30 18:28
405 查看
前言
最近好好的研究了一番移动设备的点击响应速度,期间不断的被自己坑,最后搞得焦头烂额,就是现在可能还有一些问题,但是过程中感觉自己成长不少,最后居然感觉对javascript事件机制有了更好的认识,回头来看,还是不错的,所以今天将近期的学习记录下来供后期查询
今天我们再来重新回顾下javascript的事件机制
注意:下面说的android浏览器,意思是android下多数浏览器,不包括chrome
事件基础
javascript与html之间的交互式通过事件实现的,事件是文档(窗口)中发生的一些特定交互,这些交互可以使用监听器(处理程序)预定,事件发生时就会回调我们的函数PS:这就是传说中的观察者模式,我们这里先不管他
因为我们需要确定页面哪一部分会拥有特定事件,比如内部一个span外部一个div,我们点击span时候事实上浏览器也任务div被点击了,甚至整个document也被点击了,所以引入了事件流的概念
事件流是描述从页面接收事件的顺序,现在统一有事件冒泡与事件捕获两种事件捕获流
事件冒泡/捕获
事件冒泡即由最具体的元素(文档嵌套最深节点)接收,然后逐步上传至document事件捕获会由最先接收到事件的元素然后传向最里边(我们可以将元素想象成一个盒子装一个盒子,而不是一个积木堆积)
DOM事件流
DOM2级事件规定事件包括三个阶段:① 事件捕获阶段
② 处于目标阶段
③ 事件冒泡阶段
所以说,我们同时为一个元素绑定事件(冒泡与捕获)先执行的是捕获,然后会执行冒泡
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <style type="text/css"> #p { width: 300px; height: 300px; padding: 10px; border: 1px solid black; } #c { width: 100px; height: 100px; border: 1px solid red; } </style> </head> <body> <div id="p"> parent <div id="c"> child </div> </div> <script type="text/javascript"> var p = document.getElementById('p'), c = document.getElementById('c'); c.addEventListener('click', function () { alert('子节点捕获') }, true); c.addEventListener('click', function () { alert('子节点冒泡') }, false); </script> </body> </html>
这个样子点击子元素会先执行捕获阶段注册的事件,然后执行冒泡阶段执行的事件,我们这里做一点改变
var p = document.getElementById('p'), c = document.getElementById('c'); c.addEventListener('click', function () { alert('子节点捕获') }, true); c.addEventListener('click', function () { alert('子节点冒泡') }, false); p.addEventListener('click', function () { alert('父节点捕获') }, true); p.addEventListener('click', function () { alert('父节点冒泡') }, false);
① 这个时间点击父元素会先执行父元素捕获再执行父元素冒泡
② 点击子元素会执行父元素捕获,子元素捕获,子元素冒泡,父元素冒泡
至此,我们对事件流机制应该了解一些了,于是继续往下(注意:此点知识与“鬼点击”有莫大的关系)
事件对象
事件就是用户或浏览器自身执行的某种动作(click、load),响应事件的函数就是事件处理程序(监听器)而我们的事件往往会自带一个参数——事件对象(IE那劳什子就不管了)
c.addEventListener('click', function (e) { alert('子节点捕获') }, true);
注意我们的e,他就是我们的event object了
事件对象,包含和创建他的特定事件有关的属性和方法,触发的事件不一样,参数也不一样(比如鼠标事件就会有坐标信息),我们这里题几个较重要的
PS:以下的兄弟全部是只读的,所以不要妄想去随意更改
bubbles
表明事件是否冒泡cancelable
表明是否可以取消事件的默认行为currentTarget
某事件处理程序当前正在处理的那个元素defaultPrevented
为true表明已经调用了preventDefault(DOM3新增)eventPhase
调用事件处理程序的阶段:1 捕获;2 处于阶段;3 冒泡阶段target
事件目标(绑定事件那个dom)trusted
true表明是系统的,false为开发人员自定义的(DOM3新增)type
事件类型view
与事件关联的抽象视图,发生事件的window对象preventDefault
取消事件默认行为,cancelable是true时可以使用stopPropagation
取消事件捕获/冒泡,bubbles为true才能使用stopImmediatePropagation
取消事件进一步冒泡,并且组织任何事件处理程序被调用(DOM3新增)在我们的事件处理内部,this与currentTarget相同
思考事件参数
这里有一个比较有意思的问题,说他有意思,是因为我觉得可能各位平时没有思考过:我们一次点击事件,各个事件处理的Event Object是否相同?
答案是肯定的,这里我们用IE的事件对象来说,我们是这样获得的window.event,IE这样干不是没有道理的,因为我们一次点击这个家伙是共用的!!!
事实上,我们每次鼠标操作,这个事件参数都是相同的,不信??
以PC来说,我们为movedown绑定一个事件,并且动态为e增加一个属性,newArg
window.log = function (msg) { console.log(msg) } var p = document.getElementById('p'), c = document.getElementById('c'); document.addEventListener('click', function (e) { e.newArg = '叶小钗'; }, true); c.addEventListener('click', function (e) { log(e); log('子节点捕获') }, true); c.addEventListener('click', function (e) { log(e); log('子节点冒泡') }, false); p.addEventListener('click', function (e) { log(e); log('父节点捕获') }, true); p.addEventListener('click', function (e) { log(e); log('父节点冒泡') }, false);
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <style type="text/css"> .bt { position: absolute; top: 50px; display: block; height: 50px; } </style> </head> <body> <input type="button" class="bt" value="我是快速点击事件" id="fastclick" /> <input type="text" style="width: 150px; height: 200px;" /> <div id="div" style="width: 200px; height: 200px; border: 1px solid black"> </div> </body> <script type="text/javascript"> var fastclick = document.getElementById('fastclick'); var div = document.getElementById('div'); var touch = {}; var t = new Date().getTime(); window.log = function (msg) { var d = document.createElement('div'); d.innerHTML = msg; div.appendChild(d); console.log(msg); }; document.addEventListener('click', function (event) { if (event.myclick == true) { return true; } if (event.stopImmediatePropagation) { event.stopImmediatePropagation(); } else { event.propagationStopped = true; } event.stopPropagation(); event.preventDefault(); return true; }, true); document.addEventListener('touchstart', function (e) { touch.startTime = e.timeStamp; touch.el = e.target; t = e.timeStamp; }); document.addEventListener('touchmove', function (e) { }); document.addEventListener('touchend', function (e) { touch.last = e.timeStamp; var event = document.createEvent('Events'); event.initEvent('click', true, true, window, 1, e.changedTouches[0].screenX, e.changedTouches[0].screenY, e.changedTouches[0].clientX, e.changedTouches[0].clientY, false, false, false, false, 0, null); event.myclick = true; touch.el && touch.el.dispatchEvent(event); return true; }); function fnDom(el, msg, e) { el.value = msg + '(' + (e.timeStamp - t) + ')'; el.style.display = 'none'; setTimeout(function () { el.style.display = ''; }, 1000) } fastclick.addEventListener('click', function (e) { fnDom(this, '我是快速点击事件', e); log('快速点击'); }); div.addEventListener('click', function (e) { this.innerHTML += 'div<br/>' }); </script> </html>
View Code
这种情况下,我们点击按钮,按钮消失,然后下面的input会获取焦点的!这个问题无法避免,解决方案依旧是阻止浏览器本身事件
这样在ios下面就没有问题了,当然现在我们input不能获得焦点了,但是该问题比较简单,我们暂时不管他,说下我们android下的问题
现在我们在android下,那个input非要获得焦点,这就是我们最痛恨的“点透”现象之一
该种场景比较常见:我们点击按钮出现一个弹出层,我们点击弹出层关闭按钮,正好下面有个input标签,尼玛就谈了一个键盘出来......
android问题
最后研究得出了惊人的结果,这个劳什子android里面moveover事件偶然比尼玛touchstart还快!!!而ios压根就不理睬mouseover事件,这是主要问题产生原因!!!
而android在movedown时候,开开心心触发了input的focus事件,然后键盘就弹起来了!!!
所以针对android,我们还得将mousedown干掉才行!!!!
而事实上,我们input获取焦点,就是通过mousedown触发的,ios也是
至此,我们主要问题讨论的差不多了,暂时到这里吧。
结语
今天我们一起温故了一次javascript事件相关的知识,记录了最近我遇到的一些问题供以后查询,如果这些知识对你有用就善莫大焉了相关文章推荐
- 【初窥javascript奥秘之事件冒泡】那些年我们一起冒的泡
- 【初窥javascript奥秘之事件冒泡】那些年我们一起冒的泡
- javascript之-深入事件机制
- 深入研究JavaScript的事件机制
- 浅谈JavaScript的事件机制
- JavaScript事件机制详解
- 安卓点击事件的分发机制?事件是怎么被分发的?
- android 点击事件触发机制dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
- 【移动端兼容问题研究】javascript事件机制详解(涉及移动兼容)
- 淘宝一面 关于JavaScript中的事件代理(例子:ul中无数的li上添加点击事件)
- 理解JavaScript中的事件路由冒泡过程及委托代理机制
- JavaScript 事件机制
- JavaScript基础 点击div块后背景颜色发生变化 事件的函数参数是this
- JavaScript 事件机制
- 解析Javascript事件冒泡机制
- JavaScript 点击事件
- 2016/4/1 jquery 与javascript关系 ①取元素 ②操作内容 ③操作属性 ④操作 样式 ⑤ 事件 点击变色
- javascript对点击事件和拖动事件的区分
- 关于JavaScript中的事件代理(例子:ul中无数的li上添加点击事件)
- javascript打造跨浏览器事件处理机制[Blue-Dream出品]