JS的事件冒泡和事件捕获
DOM事件流三个阶段
1.事件捕获:当鼠标触发DOM事件时,浏览器会从根节点由外到内进行事件传播。即触发子元素的事件,父元素会通过事件捕获的方式优先触发父元素的事件。
2.目标阶段:正在处理事件。
3.事件冒泡:与事件捕获相反,浏览器会从子节点由内到外进行事件传播。
DOM事件流处理顺序:先捕获,再冒泡。
具体区别
通常在addEventListener方法的第三个参数中设置true则为事件捕获,false则为事件冒泡,默认为false。
html代码:
<div id="div1"> <div id="div2"> </div> </div>
css代码:
<style> #div1 { width: 500px; height: 500px; border: 1px solid #ffffff; background: blanchedalmond; } #div2 { width: 200px; height: 200px; border: 1px solid #ffffff; background: blue; } </style>
js代码:
<script> let div1 = document.getElementById("div1"); let div2 = document.getElementById("div2"); div1.addEventListener('click', function () { console.log('div1--捕获'); }, true); div2.addEventListener('click', function () { console.log('div2--捕获'); }, true); div1.addEventListener('click', function () { console.log('div1--冒泡'); }); div2.addEventListener('click', function () { console.log('div2--冒泡'); }); </script>
点击div2打印出的结果:
由此可证上述结论即:捕获先于冒泡;对于捕获而言,外层先于内层(div1先于div2打印);对于冒泡而言,内层先于外层(div2先于div1打印)。
而我们期望的其实是对于冒泡事件,希望点击div2时仅仅只打印出div2--冒泡,修改js为:
<script> let div1 = document.getElementById("div1"); let div2 = document.getElementById("div2"); div1.addEventListener('click', function (e) { console.log('div1--冒泡'); }); div2.addEventListener('click', function (e) { console.log('div2--冒泡'); e.stopPropagation(); }); </script>
此时点击div2打印的结果:
兼容问题
IE浏览器9以下不支持e.stopPropagation();来取消冒泡事件,在IE浏览器10版本以上中已经解决该问题:
为了更好的兼容各个浏览器版本,对e.stopPropagation()事件进行一个判断:
<script> let div1 = document.getElementById("div1"); let div2 = document.getElementById("div2"); div1.addEventListener('click', function (e) { console.log('div1--冒泡'); }); div2.addEventListener('click', function (e) { console.log('div2--冒泡'); stopBubble(); }); function stopBubble (e) { if (e && e.stopPropagation) { e.stopPropagation(); } else { window.event.cancelBubble = true; } } </script>