|  
                         前言 
                        这篇博客有点长,如果你是高手请您读一读,能对其中的一些误点提出来,以免我误人子弟,并且帮助我提高 
                        如果你是javascript菜鸟,建议您好好读一读,真的理解下来会有不一样的收获 
                        在下才疏学浅,文中难免会有不同程度的错误,请您指正留言  
                        PS:事件阶段一节请看最新博客,之前理解有误 
                        javascript事件基础 
                        我们的网页之所以丰富多彩并具有交互功能,是因为我们的javascript脚本语言,而javascript与HTML之间的交互又是通过事件机制实现的 
                        所以,事件是javascript一大核心,深入了解事件机制在我们遇到较困难问题时候十分有帮助 
                        所谓事件,就是网页发生的一些瞬间(比如点击、滑动),在这些瞬间我们使用事件监听器(回调函数)去订阅事件,在事件发生时候我们的回调函数就会触发 
                        观察者模式的javascript事件机制的基石,这种异步事件编程模型,就是用户产生特定的操作,浏览器就会产生特定的事件,我们若是订阅了事件,回调就会触发 
                        好了,我们下面就来研究下javascript事件机制的几个关键点。 
                        事件捕获/冒泡 
                        网页上的布局很复杂,我们对页面的单一操作有可能产生预计以外的影响: 
                        比如我点击一个span,我可能就想点击一个span,试试上他是先点击document,然后点击事件传递到span的,而且并不会在span停下,span有子元素就会继续往下,最后会依次回传至document,我们这里偷一张图: 
                          
                        我们这里偷了一张图,这张图很好的说明了事件的传播方式 
                        事件冒泡即由最具体的元素(文档嵌套最深节点)接收,然后逐步上传至document 
                        事件捕获会由最先接收到事件的元素然后传向最里边(我们可以将元素想象成一个盒子装一个盒子,而不是一个积木堆积) 
                        这里我们进入dom事件流,这里我们详细看看javascript事件的传递方式 
                        DOM事件流 
                        DOM2级事件规定事件包括三个阶段: 
                        ① 事件捕获阶段 
                        ② 处于目标阶段 
                        ③ 事件冒泡阶段 
                        这里说起来不太明显,我们来一个例子吧: 
                        http://sandbox.runjs.cn/show/l31ucooa 
                        
                           
                             <html xmlns="http://www.w3.org/1999/xhtml">  2 <head>  3     <title></title>  4     <style type="text/css">  5          #p { width: 300px; height: 300px; padding: 10px;  border: 1px solid black; }  6          #c { width: 100px; height: 100px; border: 1px solid red; }  7     </style>  8 </head>  9 <body> 10     <div id="p"> 11         parent 12         <div id="c"> 13             child 14         </div> 15     </div> 16     <script type="text/javascript"> 17         var p = document.getElementById('p'), 18             c = document.getElementById('c'); 19         c.addEventListener('click', function () { 20             alert('子节点捕获') 21         }, true); 22  23         c.addEventListener('click', function () { 24             alert('子节点冒泡') 25         }, false); 26     </script> 27 </body> 28 </html>  | 
                           
                         
                        这个代码比较简单,我们主要点击child即可,这里要证明的就是点击事件是先捕获再冒泡,所以我们这里来一个复杂点的关系: 
                        http://sandbox.runjs.cn/show/ij4rih6x 
                        
                           
                             <html xmlns="http://www.w3.org/1999/xhtml">  2 <head>  3     <title></title>  4     <style type="text/css">  5          #p { width: 300px; height: 300px; padding: 10px;  border: 1px solid black; }  6          #c { width: 100px; height: 100px; border: 1px solid red; }  7     </style>  8 </head>  9 <body> 10     <div id="p"> 11         parent 12         <div id="c"> 13             child 14         </div> 15     </div> 16     <script type="text/javascript"> 17         var p = document.getElementById('p'), 18         c = document.getElementById('c'); 19         c.addEventListener('click', function () { 20             alert('子节点捕获') 21         }, true); 22  23         c.addEventListener('click', function () { 24             alert('子节点冒泡') 25         }, false); 26  27         p.addEventListener('click', function () { 28             alert('父节点捕获') 29         }, true); 30  31         p.addEventListener('click', function () { 32             alert('父节点冒泡') 33         }, false); 34     </script> 35 </body> 36 </html>  | 
                           
                         
                        现在这个家伙就比较实在了,不注意就容易晕的,我们来稍微理一理: 
                        ① 点击parent,事件首先在document上然后parent捕获到事件,处于目标阶段然后event.target也等于parent,所以触发捕获事件 
                        由于target与currentTarget相等了,所以认为到底了,开始冒泡,执行冒泡事件 
                        ② 点击child情况有所不同,事件由document传向parent执行事件,然后传向child最后开始冒泡,所以执行顺序各位一定要清晰 
                          
                        至此,我们事件传输结束,下面开始研究事件参数  
                        事件对象 
                        所谓事件对象,是与特定对象相关,并且包含该事件详细信息的对象。 
                        事件对象作为参数传递给事件处理程序(IE8之前通过window.event获得),所有事件对象都有事件类型type与事件目标target(IE8之前的srcElement我们不关注了) 
                        各个事件的事件参数不一样,比如鼠标事件就会有相关坐标,包含和创建他的特定事件有关的属性和方法,触发的事件不一样,参数也不一样(比如鼠标事件就会有坐标信息),我们这里题几个较重要的 
                        PS:以下的兄弟全部是只读的,所以不要妄想去随意更改,IE之前的问题我们就不关注了 
                        bubbles 
                        表明事件是否冒泡 
                        cancelable 
                        表明是否可以取消事件的默认行为 
                        currentTarget 
                        某事件处理程序当前正在处理的那个元素 
                        defaultPrevented 
                        为true表明已经调用了preventDefault(DOM3新增) 
                        eventPhase 
                        调用事件处理程序的阶段:1 捕获;2 处于阶段;3 冒泡阶段 
                        这个属性的变化需要在断点中查看,不然你看到的总是0 
                        target 
                        事件目标(绑定事件那个dom) 
                        trusted 
                        true表明是系统的,false为开发人员自定义的(DOM3新增) 
                        type 
                        事件类型 
                        view 
                        与事件关联的抽象视图,发生事件的window对象 
                        preventDefault 
                        取消事件默认行为,cancelable是true时可以使用 
                        stopPropagation 
                        取消事件捕获/冒泡,bubbles为true才能使用 
                        stopImmediatePropagation 
                        取消事件进一步冒泡,并且组织任何事件处理程序被调用(DOM3新增) 
                        在我们的事件处理内部,this与currentTarget相同 
                        createEvent 
                        可以在document对象上使用createEvent创建一个event对象 
                         DOM3新增以下事件:  
                        UIEvents  
                        MouseEvents  
                        MutationEvents,一般化dom变动  
                        HTMLEvents一般dom事件 
                        创建鼠标事件时需要创建的事件对象需要提供指定的信息(鼠标位置信息),我们这里提供以下参数: 
                        
                           
                             var type = 'click'; //要触发的事件类型  2 var bubbles = true; //事件是否可以冒泡  3 var cancelable = true; //事件是否可以阻止浏览器默认事件  4 var view = document.defaultView; //与事件关联的视图,该属性默认即可,不管  5 var detail = 0;  6 var screenX = 0;  7 var screenY = 0;  8 var clientX = 0;  9 var clientY = 0; 10 var ctrlKey = false; //是否按下ctrl 11 var altKey = false; //是否按下alt 12 var shiftKey = false; 13 var metaKey = false; 14 var button = 0;//表示按下哪一个鼠标键 15 var relatedTarget = 0; //模拟mousemove或者out时候用到,与事件相关的对象 16  17 var event = document.createEvent('MouseEvents'); 18 event.initMouseEvent(type, bubbles, cancelable, view, detail, screenX, screenY, clientX, clientY,  19 ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);  | 
                           
                         
                        如此,我们就自己创建了一个event对象,然后可以传给我们自己创建的事件,这个知识点,我们下面再说 
                        PS:值得注意的是,我们自己创建的event对象可以有一点不一样的东西,比如我们的事件对象可能多了一个这种属性: 
                        
                        事件模拟 
                        事件模拟是javascript事件机制中相当有用的功能,理解事件模拟与善用事件模拟是判别一个前端的重要依据,所以各位一定要深入理解(我理解较水) 
                        事件一般是由用户操作触发,其实javascript也是可以触发的,比较重要的是,javascript的触发事件还会冒泡哦!!! 
                        意思就是,javascript触发的事件与浏览器本身触发其实是一样的(并不完全一致) 
                        如此,我们这里来通过键盘事件触发刚刚的点击事件吧,我们这里点击键盘便触发child的点击,看看他的表现如何 
                        PS:由于是键盘触发,便不具有相关参数了,我们可以捕捉event参数,这对我们队事件传输的理解有莫大的帮助: 
                        我们这里先创建事件参数,然后给键盘注册事件,在点击键盘时候便触发child的点击事件,各位试试看: 
                        PS:这个可能需要打开网页点击空格测试了 
                        http://sandbox.runjs.cn/show/pesvelp1 
                        
                           
                             <html xmlns="http://www.w3.org/1999/xhtml">  2 <head>  3     <title></title>  4     <style type="text/css">  5          #p { width: 300px; height: 300px; padding: 10px;  border: 1px solid black; }  6          #c { width: 100px; height: 100px; border: 1px solid red; }  7     </style>  8 </head>  9 <body> 10     <div id="p"> 11         parent 12         <div id="c"> 13             child 14         </div> 15     </div> 16     <script type="text/javascript"> 17         alert = function (msg) { 18             console.log(msg); 19         } 20  21         var p = document.getElementById('p'), 22         c = document.getElementById('c'); 23         c.addEventListener('click', function (e) { 24             console.log(e); 25             alert('子节点捕获') 26         }, true); 27         c.addEventListener('click', function (e) { 28             console.log(e); 29             alert('子节点冒泡') 30         }, false); 31  32         p.addEventListener('click', function (e) { 33             console.log(e); 34             alert('父节点捕获') 35         }, true); 36  37         p.addEventListener('click', function (e) { 38             console.log(e); 39             alert('父节点冒泡') 40         }, false); 41  42         document.addEventListener('keydown', function (e) { 43             if (e.keyCode == '32') { 44                 var type = 'click'; //要触发的事件类型 45                 var bubbles = true; //事件是否可以冒泡 46                 var cancelable = true; //事件是否可以阻止浏览器默认事件 47                 var view = document.defaultView; //与事件关联的视图,该属性默认即可,不管 48                 var detail = 0; 49                 var screenX = 0; 50                 var screenY = 0; 51                 var clientX = 0; 52                 var clientY = 0; 53                 var ctrlKey = false; //是否按下ctrl 54                 var altKey = false; //是否按下alt 55                 var shiftKey = false; 56                 var metaKey = false; 57                 var button = 0; //表示按下哪一个鼠标键 58                 var relatedTarget = 0; //模拟mousemove或者out时候用到,与事件相关的对象 59                 var event = document.createEvent('Events'); 60                 event.myFlag = '叶小钗'; 61                 event.initEvent(type, bubbles, cancelable, view, detail, screenX, screenY, clientX, clientY, 62 ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget); 63                  64                 console.log(event); 65                 c.dispatchEvent(event); 66             } 67         }, false); 68     </script> 69 </body> 70 </html>  | 
                           
                          
                        各位,这里看到了与之前的相同或者不同吗???这些都是很关键的哦,其实主要不同就是我们的事件参数没了鼠标位置,多了一个属性: 
                          
                          
                        这里有两点容易让各位造成错觉: 
                        ① firefox并不会将myFlag显示到console下面 
                        ② chrome如果使用原生alert会阻止第一次父元素捕获,所以各位一定要注意 
                        然后这里还有一个小小知识点: 
                        使用dom.dispatchEvent(event)触发模拟事件 
                        移动端响应速度 
                        有了以上知识点,其实对PC端来说基本够用了,如果再稍微研究下jquery源码就善莫大焉了,但是在移动端却有所不同,我们这里还得来理一理 
                        PS:我这里主要针对点击事件 
                        PC与移动端鼠标事件差异 
                        首先,在移动端mouse事件好像就有点不那么适用了,倒不是说touch事件要比mouse事件好,其实他们底层原理相距不大,主要不同点就是: 
                        移动端会多点触屏 
                        多点触屏就带来了事件对象参数的差异,比如说: 
                           
                        changedTouches/touches/targetTouches 
                        touches:为屏幕上所有手指的信息 
                        PS:因为手机屏幕支持多点触屏,所以这里的参数就与手机有所不同 
                        targetTouches:手指在目标区域的手指信息 
                        changedTouches:最近一次触发该事件的手指信息 
                        比如两个手指同时触发事件,2个手指都在区域内,则容量为2,如果是先后离开的的话,就会先触发一次再触发一次,这里的length就是1,只统计最新的 
                        PS:一般changedTouches的length都是1 
                        touchend时,touches与targetTouches信息会被删除,changedTouches保存的最后一次的信息,最好用于计算手指信息 
                        这里要使用哪个数据各位自己看着办吧,我也不是十分清晰(我这里还是使用changedTouches吧) 
                        以上就是mouse与touch主要不同点,但这些并不是太影响我们的操作,因为到现在为止,我们一般还是使用的是单击 
                        小贴士 
                        国内SPA网站模式较少,目前为止还是以单个网页为主,spa模式对javascript技术要求较高不说,首次加载量大也是不可避免的问题 
                        加之移动端设备今年才普及,而且各自争夺领地、争夺入口,还有其他原因,反正现况是有时做移动端的兼容比做IE的兼容还难 
                        就拿简单的CSS3动画来说,在ios下就有闪动现象,而且还是iPhone4s,就现今更新换代来说,此种情况并不会得到明显好转,而且CSS3动画状态保存问题亦是一大难题 
                        另外,网页想要检测手机是否安装APP也是有很大缺陷,移动端的fixed更不要说,这些问题都需要我们乃至开发商解决 
                        PS:这里扯得有点远,我们继续下面的话题 
                        touch与click响应速度问题 
                        click本身在移动端响应是没有问题的,但是我们点击下来300ms 的延迟却是事实,这种事实造成的原因就是 
                        手机需要知道你是不是想双击放大网页内容 
                        所以click点击响应慢,而touch却不会有这样的限制,于是移动端的touch相当受欢迎,至于鼠标慢,他究竟有多慢,我们来看看: 
                        现在我们在手机上同时触发两者事件看看区别: 
                        
                           
                             <!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>     <script id="others_zepto_10rc1" type="text/javascript" class="library" 
src="http://sandbox.runjs.cn/js/sandbox/other/zepto.min.js"></script> </head> <body>     <div id="d" style="width: 100px; height: 100px; border: 1px solid black;">     </div> </body> <script type="text/javascript">     var startTime;     var log = function (msg) {         var div = $('<div></div>');         div.html((new Date().getTime()) + ': ' + (new Date().getTime() - startTime) + ': ' + msg)         $('body').append(div);
};     var touchStart = function () {         startTime = new Date().getTime();         log('touchStart');     };     var touchEnd = function () {         log('touchEnd');
};     var mouseDown = function () {         log('mouseDown');     };     var mouseClick = function () {         log('mouseClick');     };     var mouseUp = function () {         log('mouseUp'); 
};     var d = $('#d');     d.bind('mousedown', mouseDown);     d.bind('click', mouseClick);     d.bind('mouseup', mouseUp);     d.bind('touchstart', touchStart);     d.bind('touchend', touchEnd); </script> </html> 
                               | 
                           
                         
                        测试地址:(使用手机) 
                        http://sandbox.runjs.cn/show/ey54cgqf 
                        此处手机与电脑有非常大的区别!!! 
                        结论部分将在下篇讲述,明天发布,请继续支持本网站。 
                         |