1、首先我们要弄清楚当一个dom事件被触发时,它不仅仅只是单纯地在自身对象上触发一次,而是经历了三个不同的阶段:👇 捕获阶段:先由文档的根节点document往事件触发对象,从外向内捕获事件对象; 目标阶段:到达目标事件位置,触发事件; 冒泡阶段:再从目标事件位置往文档的根节点方向回溯,从内向外冒泡事件对象。
2、下面贴上一张 w3c解释事件流 的图:
1、当我们注册一个事件时,事件默认使用冒泡事件流,不使用捕获事件流。
element.addEventListener(event, function, useCapture)event: 必须。字符串,指定事件类型。 function: 必须。指定要事件触发时执行的函数。 useCapture: 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。false为冒泡(默认),true为捕获。
2、下面在代码中验证,直接附上全部代码。(可以粘到自己编辑器中运行、尝试一下)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>event</title> <style> #one{ width: 600px; height: 600px; background-color: green; } #two{ width: 400px; height: 400px; background-color: yellow; } #three{ width: 200px; height: 200px; background-color: deepskyblue; } </style> </head> <body> <div id="one">one <div id="two">two <div id="three">three</div> </div> </div> <script> var one = document.getElementById('one'), two = document.getElementById('two'), three = document.getElementById('three'); one.addEventListener('click', function(){ console.log('one捕获') }, true) two.addEventListener('click', function(){ console.log('two捕获') }, true) three.addEventListener('click', function(){ console.log('three捕获') }, true) one.addEventListener('click', function(){ console.log('one冒泡') }, false) two.addEventListener('click', function(){ console.log('two冒泡') }, false) three.addEventListener('click', function(){ console.log('three冒泡') }, false) </script> </body> </html>3、当我们点击three时,可以看到确实是先由外向内事件捕获,一直到事发元素,再由内向外冒泡到根节点上。 4、如果一个元素既注册了冒泡事件,也注册了捕获事件,则按照注册顺序执行。 我们修改代码把冒泡事件放在捕获事件之前:
one.addEventListener('click', function(){ console.log('one冒泡') }, false) two.addEventListener('click', function(){ console.log('two冒泡') }, false) three.addEventListener('click', function(){ console.log('three冒泡') }, false) one.addEventListener('click', function(){ console.log('one捕获') }, true) two.addEventListener('click', function(){ console.log('two捕获') }, true) three.addEventListener('click', function(){ console.log('three捕获') }, true)再点击three,可以看到这次three先是执行冒泡后捕获的,由此可见一个元素同时注册了冒泡和捕获事件,则会按照注册顺序执行。
1、在很多时候我们并不需要元素绑定的事件向外冒泡,这时我们就要阻止事件的冒泡。 阻止冒泡:w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true; 我们再次修改代码,阻止three的事件冒泡:
three.addEventListener('click', function(){ console.log('three冒泡') var e = e || window.event; // firefox下window.event为null, IE下event为null // 阻止冒泡 if(e.stopPropagation){ e.stopPropagation() //其他浏览器 }else{ e.cancelBubble = true //IE浏览器 } }, false)修改完代码后我们再次点击three,可以看到three的点击事件触发后就停止继续向外冒泡了;