这个问题的整理是基于面试题:
给同一个DOM元素绑定两个事件,一个用冒泡,一个用捕获,会执行几次?先执行冒泡还是先执行捕获?
例子:
<div id="outer">
<p id="inner">Click me!</p>
</div>
事件冒泡:
微软提出了名为事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
因此上面的例子在事件冒泡的概念下发生click事件的顺序应该是p -> div -> body -> html -> document
事件捕获:
网景提出另一种事件流名为事件捕获(event capturing)。与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。
上面的例子在事件捕获的概念下发生click事件的顺序应该是document -> html -> body -> div -> p
如下代码,有四个div嵌套元素,均绑定了click事件,addEventListener函数的第三个参数设置为false说明不为捕获事件,即为冒泡事件。该代码执行结果如下:
点击one元素,输出one;
点击two元素,输出two one;
点击three元素,输出 three two one;
点击four元素,输出 four three two one;
<div id='one'>
<div id='two'>
<div id='three'>
<div id='four'>
</div>
</div>
</div>
</div>
<script>
var one=document.getElementById('one');
var two=document.getElementById('two');
var three=document.getElementById('three');
var four=document.getElementById('four');
one.addEventListener('click',function(){
alert('one');
},false);
two.addEventListener('click',function(){
alert('two');
},false);
three.addEventListener('click',function(){
alert('three');
},false);
four.addEventListener('click',function(){
alert('four');
},false);
</script>
而捕获则相反。当触发目标元素时,会从目标元素的最顶层的祖先元素事件往下执行到目标元素为止。
将上面的代码第三个参数均改为true,则执行结果如下:
点击one,输出one;
点击two,输出one two;
点击three,输出one two three;
点击four,输出one two three four;
很明显执行顺序是不同的。
问题解释:
无论是冒泡事件还是捕获事件,元素都会先执行捕获阶段
从上往下,如有捕获事件,则执行;一直向下到目标元素后,从目标元素开始向上执行冒泡元素
如下代码:
此时点击four元素,four元素为目标元素,one为根元素祖先,从one开始向下判断执行。
one为捕获事件,输出one;
two为冒泡事件,忽略;
three为捕获时间,输出three;
four为目标元素,开始向上冒泡执行,输出four;(从此处分为两部分理解较容易。)
three为捕获已执行,忽略;
two为冒泡事件,输出two;
one为捕获已执行,忽略。
最终执行结果为:one three four two
one.addEventListener('click',function(){
alert('one');
},true);
two.addEventListener('click',function(){
alert('two');
},false);
three.addEventListener('click',function(){
alert('three');
},true);
four.addEventListener('click',function(){
alert('four');
},false);
执行次数:绑定了几个事件便执行几次。
如下代码,two元素绑定了两个不同事件,点击two都会执行这两个事件。而执行顺序有所差异
1、如果two为目标元素,目标元素的事情按顺序执行,而其他元素根据W3C的标准执行,即先捕获后冒泡。
点击two执行结果:one(因为是two的父元素支持捕获事件所以先执行) two,bubble two,capture(顺序执行,注意逗号不是间隔,是输出内容。)
2、如果目标元素不是two,则two的两个事件按先捕获后冒泡触发执行,也就是跟前面讨论的执行过程是一样的,只不过两个事件都绑定在同一个DOM元素上。
点击three执行结果:one two,capture three,capture two,bubble
one.addEventListener('click',function(){
alert('one');
},true);
two.addEventListener('click',function(){
alert('two,bubble');
},false);
two.addEventListener('click',function(){
alert('two,capture');
},true);
three.addEventListener('click',function(){
alert('three,capture');
},true);
four.addEventListener('click',function(){
alert('four,capture');
},true);