JavaScript的事件冒泡和事件捕获,均是为了解决页面中事件流(事件发生顺序)的问题
注:事件的冒泡和捕获是事件流的过程,在具体的实例写法上,存在捕获留写法和冒泡流写法(需分清概念)
- 事件冒泡流:即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的那个节点(document)
- 事件捕获流:与冒泡流截然相反,它的定义是最不具体的节点应该更早接收到事件,而最具体的节点最后接收到事件
感觉概念很绕(冒泡:如果在某一个对象上触发某一类事件,那么该事件会向父级传播,并触发父对象上定义的同类事件)
一般在实际应用时,为了兼容性,更多使用冒泡流的写法
以一个具体的click事件为例(捕获流的写法):
<ul id="app"> <li>event_1</li> <li>event_2</li> <li>event_3</li> </ul>
要实现点击li,出现弹框提示,会将过程写为:
首先找到ul,然后遍历li,点击li的时候,找一次目标的li的位置,执行最后的操作(捕获事件)。
window.onload = function(){ var event = document.getElementById("app"); var click = event.getElementsByTagName('li'); for(var i=0;i<click.length;i++){ click[i].onclick = function(){ alert("点击了列表"); } } }
或用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发。
window.onload = function(){ var event = document.getElementById("app"); event.onclick = function(){ alert(123); } }
同样是一个具体的click事件,解释冒泡流写法:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件流</title> <style type="text/css"> #content { width: 150px; height: 150px; background-color: red; } #btn { width: 80px; height: 80px; background-color: green; } </style> </head> <body> <div id="content">content <div id="btn">button</div> </div> <script type="text/javascript"> var content = document.getElementById("content"); var btn = document.getElementById('btn'); btn.onclick = function () { alert("btn"); }; content.onclick = function () { alert("content"); }; document.onclick = function () { alert("document"); } </script> </body> </html>
运行时,会得到:
- 当点击绿色的button时,首先弹出"btn",后弹出"content",最后弹出"document"
- 点击红色content时,首先弹出"content",后弹出"document"
上例代码中,点击绿色button,会首先响应btn上的弹出事件,而后,由于冒泡机制(个人理解为包含或者认为是图片位置的层叠,下层存在content的图片被点击,同时button在文档内,也可认为是点击了文档内任意区域),于是会响应content上的事件,最后冒泡到document上的事件响应
好像还是有点绕,把这一段代码放浏览器运行一下就很容易明白了
由此,引入事件流的示意图如下所示,可以知道:
- 一个完整的JS事件流是从window开始,最后回到window的一个过程
- 事件的冒泡和捕获属于两个相反的过程
- 事件流被分为三个阶段:
- 捕获阶段:在事件冒泡的模型中,捕获阶段不会响应任何事件;
- 目标阶段:目标阶段就是指事件响应到触发事件的最底层元素上;
- 冒泡阶段:冒泡阶段就是事件的触发响应会从最底层目标一层层地向外到最外层(根节点)