事件冒泡
和事件捕获
分别由微软
和网景
公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题。
<div id='aa' click='po'> <p id='bb' click='on'>点击</p> </div>
上面两个点击事件如果点击的时候,到底谁会被先触发呢,为了解决这个问题微软和网景提出了两种几乎完全相反的概念。
事件冒泡
微软提出了名为事件冒泡(event bubbling)
的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
因此在事件冒泡的概念下在p元素上发生click事件的顺序应该是p -> div -> body -> html -> document
事件捕获
网景提出另一种事件流名为事件捕获(event capturing)
。与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。
因此在事件捕获的概念下在p元素上发生click事件的顺序应该是document -> html -> body -> div -> p
后来 w3c 采用折中的方式,平息了战火,制定了统一的标准——先捕获再冒泡。
冒泡的案例
<div id="s1">s1 <div id="s2">s2</div> </div> <script> s1.addEventListener("click",function(e){ console.log("s1 冒泡事件"); },false); s2.addEventListener("click",function(e){ console.log("s2 冒泡事件"); },false); </script>
捕获的案例
<div id="s1">s1 <div id="s2">s2</div> </div> <script> s1.addEventListener("click",function(e){ console.log("s1 捕获事件"); },true); s2.addEventListener("click",function(e){ console.log("s2 捕获事件"); },true); </script>
当事件冒泡和捕获在一起出现的时候
<div id="s1">s1 <div id="s2">s2</div> </div> <script> s1.addEventListener("click",function(e){ console.log("s1 冒泡事件"); },false); s2.addEventListener("click",function(e){ console.log("s2 冒泡事件"); },false); s1.addEventListener("click",function(e){ console.log("s1 捕获事件"); },true); s2.addEventListener("click",function(e){ console.log("s2 捕获事件"); },true); </script>
-
对于非被点击dom节点则先执行捕获在执行冒泡
-
对于被点击的dom节点则是先执行先注册的事件,无论冒泡还是捕获
事件冒泡和捕获,衍生出事件委托,因为当你点击子元素的时候,实际上走的是父组件的事件
<ul id="list"> <li>111</li> <li>2222</li> </ul>
点击子元素的时候,由父元素去代为执行,能减少事件输出,代码的编写量
取消默认事件
w3c 的方法是 e.preventDefault(),IE 则是使用 e.returnValue = false;
取消默认事件,还可以用return来进行阻止
阻止冒泡的事件
w3c 的方法是 e.stopPropagation(),IE 则是使用 e.cancelBubble = true
IE9 之前的IE不支持 stopPropagation() 方法。相反,IE事件对象有一个 cancleBubble 属性,设置这个属性为 true 能阻止事件进一步传播。( IE8 及之前版本不支持事件传播的捕获阶段,所以冒泡是唯一待取消的事件传播。)
冒泡事件案例:
<div id='div' onclick='alert("div");'> <ul onclick='alert("ul");'> <li onclick='alert("li");'>test</li> </ul> </div>
正常情况下,li>ul>div,这就是正常的冒泡的事件
阻止冒泡的事件:
window.event? window.event.cancelBubble = true : e.stopPropagation();
阻止冒泡事件,案例
<html> <head> <style> #a{ 300px; height: 300px; background: pink; } #b{ 200px; height: 200px; background: blue; } #c{ 100px; height: 100px; background: yellow; } </style> </head> <body> <div id="a"> <div id="b"> <div id="c"></div> </div> </div> <script> var a = document.getElementById("a"), b = document.getElementById("b"), c = document.getElementById("c"); c.addEventListener("click", function (event) { console.log("c1"); event.stopImmediatePropagation(); // 注意第三个参数没有传进 false , 因为默认传进来的是 false //,代表冒泡阶段调用,个人认为处于目标阶段也会调用的 }); c.addEventListener("click", function (event) { console.log("c2"); }, true); b.addEventListener("click", function (event) { console.log("b"); }, true); a.addEventListener("click", function (event) { console.log("a1"); }, true); a.addEventListener("click", function (event) { console.log("a2") }); a.addEventListener("click", function (event) { console.log("a3"); event.stopImmediatePropagation(); }, true); a.addEventListener("click", function (event) { console.log("a4"); }, true); </script> </body> </html>
当时写博客的时候忘了写阻止冒泡的事件了,多谢老铁提醒!!!