DOM事件阶段以及事件捕获与事件冒泡先后执行顺序
平时浏览这么多技术文章,如过不去实践、深入弄透它,这个技术点很快就会在脑海里模糊。要加深印象,就得好好过一遍。重要的事情说三遍,重要的知识写一遍。
开发过程中我们都希望使用别人成熟的框架,因为站在巨人的肩膀上会使得我们开发的效率大幅度提升。不过,我们也应该、必须了解其基本原理。比如DOM事件,jquery框架帮我们为我们封装和抽象了各浏览器的差异行为,为事件处理带来了极大的便利。不过浏览器逐步走向统一和标准化,我们可以更加安全地使用官方规范的接口。因为只有获得众多开发者的芳心,浏览器才会走得更远。正如我们现在使用低版本浏览器打开某些页面时,会告知我们要用chrome等高级浏览器访问。不过这是一个革命的过程,为了让我们的webPage更好地服务更多的人,现在我们还不得不对这些历史遗留问题做更好的兼容。要做好兼容,除了依赖框架,我们得理解其基本原理。
DOM事件三个阶段
当一个DOM事件被触发时,它不仅仅只是单纯地在本身对象上触发一次,而是会经历三个不同的阶段:
- 捕获阶段:先由文档的根节点document往事件触发对象,从外向内捕获事件对象;
- 目标阶段:到达目标事件位置(事发地),触发事件;
- 冒泡阶段:再从目标事件位置往文档的根节点方向回溯,从内向外冒泡事件对象。
引用来源:http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
事件捕获与事件冒泡先后执行顺序就显而易见了。
实验部分
打开在线编辑器:http://jsbin.com/goqede/edit?html,css,js,output
代码如下:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <style> 7 #outer{ 8 text-align: center; 9 width: 400px; 10 height: 400px; 11 background-color: #ccc; 12 margin: 0 auto; 13 } 14 #middle{ 15 width: 250px; 16 height: 250px; 17 background-color: #f00; 18 margin: 0 auto; 19 } 20 #inner{ 21 width: 100px; 22 height: 100px; 23 background-color: #0f0; 24 margin: 0 auto; 25 border-rad 26 } 27 </style> 28 </head> 29 <body> 30 <div id='outer'> 31 <span>outer</span> 32 <div id='middle'> 33 <span>middle</span> 34 <div id='inner'> 35 <span>inner</span> 36 </div> 37 </div> 38 </div> 39 <script> 40 function $(element){ 41 return document.getElementById(element); 42 } 43 function on(element,event_name,handler,use_capture){ 44 if(addEventListener){ 45 $(element).addEventListener(event_name,handler,use_capture); 46 } 47 else{ 48 $(element).attachEvent('on'+event_name,handler); 49 } 50 } 51 52 on("outer","click",o_click_c,true); 53 on("middle","click",m_click_c,true); 54 on("inner","click",i_click_c,true); 55 56 on("outer","click",o_click_b,false); 57 on("middle","click",m_click_b,false); 58 on("inner","click",i_click_b,false); 59 60 61 62 function o_click_c(){ 63 console.log("outer_捕获"); 64 alert("outer_捕获"); 65 } 66 function m_click_c(){ 67 console.log("middle_捕获") 68 alert("middle_捕获"); 69 } 70 function i_click_c(){ 71 console.log("inner_捕获") 72 alert("inner_捕获"); 73 } 74 function o_click_b(){ 75 console.log("outer_冒泡") 76 alert("outer_冒泡"); 77 } 78 function m_click_b(){ 79 console.log("middle_冒泡") 80 alert("middle_冒泡"); 81 } 82 function i_click_b(){ 83 console.log("inner_冒泡") 84 alert("inner_冒泡"); 85 } 86 </script> 87 </body> 88 </html>
当我们点击inner的时候结果是:
outer_捕获
middle_捕获
inner_捕获
inner_冒泡
middle_冒泡
outer_冒泡
由此可见:确实是先由外向内事件捕获,一直到事发元素,在由内向外冒泡到根节点上
tips:
当事件触发在目标阶段时,会根据事件注册的先后顺序执行,在其他两个阶段注册顺序不影响事件执行顺序。也就是说如果该处既注册了冒泡事件,也注册了捕获事件,则按照注册顺序执行。
例如当我点击inner的时候,按照以上顺序,答案确实是我们想要的答案:
、
当我的事件注册顺序改变成如下代码时:
当我们点击outer时:
当我们点击middle时:
当我们点击inner时:
可以看出在目标阶段的事发元素上的事件执行顺序是有事件注册顺序决定的