参考文章:https://www.jb51.net/article/94394.htm
W3C 中定义事件的发生经历三个阶段:
捕获阶段(capturing)、目标阶段(targetin)、冒泡阶段(bubbling)
- 冒泡型事件:当你使用事件冒泡时,子级元素先触发,父级元素后触发
- 捕获型事件:当你使用事件捕获时,父级元素先触发,子级元素后触发
DOM
事件流:同时支持两种事件模型:捕获型事件和冒泡型事件
阻止事件发生的方法:
- 阻止冒泡:在
W3c
中,使用 stopPropagation() 方法;在IE下设置 cancelBubble = true - 阻止捕获:阻止事件的默认行为,例如 click - <a> 后的跳转。在W3c中,使用 preventDefault() 方法,在 IE 下设置 window.event.returnValue = false
再谈事件函数执行先后顺序:
利用 addEventListener() 在元素上绑定多个事件,且设置不同的事件流。也就是说,先后绑定两个click 事件,一个设置事件冒泡,一个设置事件捕获
我们在outC上触发onclick事件(这个是目标对象),如果我们在outC上同时绑定捕获阶段/冒泡阶段事件处理函数会怎么样呢?
<script>
window.onload = function(){
var outA = document.getElementById("outA");
var outB = document.getElementById("outB");
var outC = document.getElementById("outC");
// 目标(自身触发事件,是冒泡还是捕获无所谓)
outC.addEventListener('click',function(){console.log("target2");},true);
outC.addEventListener('click',function(){alert("target1");},true);
// 事件冒泡
outB.addEventListener('click',function(){alert("bubble2");},false);
outA.addEventListener('click',function(){alert("bubble1");},false);
// 事件捕获
outB.addEventListener('click',function(){alert("capture2");},true);
outA.addEventListener('click',function(){alert("capture1");},true);
</script>
<body>
<div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
<div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
<div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
</div>
</div>
</body>
点击outC的时候,打印顺序是:capture1-->capture2-->target2-->target1-->bubble2-->bubble1。
捕获事件最后才绑定 ,但是最先执行了;然后是目标阶段的事件;最后是冒泡事件。
捕获事件 --> 目标阶段 --> 冒泡事件
由于outC是我们触发事件的目标对象,在outC上注册的事件处理函数,属于DOM事件流中的目标阶段。目标阶段函数的执行顺序:先注册的先执行,后注册的后执行。这就是上面我们说的,在目标对象上绑定的函数是采用捕获,还是采用冒泡,都没有什么关系,因为冒泡和捕获只是对父元素上的函数执行顺序有影响,对自己没有什么影响。如果不信,可以将下面的代码放进去验证。
// 目标(自身触发事件,是冒泡还是捕获无所谓)
outC.addEventListener('click',function(){console.log("target1");},false);
outC.addEventListener('click',function(){console.log("target2");},true);
outC.addEventListener('click',function(){console.log("target3");},true);
outC.addEventListener('click',function(){console.log("target4");},false);
至此我们可以给出事件函数执行顺序的结论了:捕获阶段的处理函数最先执行,其次是目标阶段的处理函数,最后是冒泡阶段的处理函数。目标阶段的处理函数,先注册的先执行,后注册的后执行。