今天看到阿里的一道面试题:
- 如果给一个元素绑定了4个事件处理(用addEventListener),其中两个是capture, 两个冒泡,那么触发顺序是什么?
看完之后开始找答案,然后写个栗子测试了一下:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div> <input type="button" id="btn_test" value="测试" /> </div> <script> window.onload=function(){ var oBtn = document.getElementById("btn_test"); if (oBtn.attachEvent) { //IE 中 oBtn.attachEvent("onclick",test1); oBtn.attachEvent("onclick",test2); oBtn.attachEvent("onclick",test3); oBtn.attachEvent("onclick",test4); } else{ oBtn.addEventListener("click",test1,false);//冒泡
oBtn.addEventListener("click",test2,false); //冒泡
oBtn.addEventListener("click",test3,true);//捕获
oBtn.addEventListener("click",test4,true); //捕获
} function test1(){ console.log("test1") } function test2(){ console.log("test2") } function test3(){ console.log("test3") } function test4(){ console.log("test4") } } </script> </body> </html>
测试结果如下:
ie6:结果是随机的;
ie7-8结果如下图:
ie9结果如下图:
非ie浏览器结果如下:
由于ie7~ie9测试结果我是用浏览器模拟的,不确定这几种浏览器版本的结果准确性,由此可看,执行顺序应该是这样的:
捕获比冒泡先触发,但同级哪个函数先触发,不同浏览器有差异。非IE浏览器是按照绑定顺序执行,IE好像是随机(ps:我在js高级程序设计一书中中看到是这样说的----这些事件处理程序不是已添加它们的顺序执行,而是以相反的顺序被触发)。
下面我对如上知识做一下补充:
(1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。
(2)捕获型事件(event capturing):事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。
(3)DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件,但是,捕获型事件先发生。两种事件流会触及DOM中的所有对象,从document对象开始,也在document对象结束。
支持W3C标准的浏览器在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。而不兼容W3C的浏览器(IE)用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。
事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)。
事件冒泡阶段:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。
//冒泡