事件,就是文档或浏览器窗口发生的一些特定的交互瞬间。(by 《JavaScript高级程序设计》)
好比鼠标点击,双击,滚动条滑动...javascript
先来看一个简单的例子:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="main"> <div class="btn-wrap"> <button id="btn">点击</button> </div> <div> </body> </html>
这时候咱们点击btn
的同时,也能够视为同时点击了btn
的容器元素,甚至单击了整个页面。
事件流指的是从页面接收事件的顺序。
关于事件流,IE和Netscape提出了差很少相反的概念,IE提出的就是广为人知的事件冒泡流,而Netscape提出的则是事件捕获流。java
事件冒泡,即事件开始时由最具体的元素接收,如上面例子中的btn
,而后逐渐向上级传播到较为不具体的节点。DOM2级事件
规定addEventListener
方法的第三个参数设为false
,表示事件在冒泡阶段触发。浏览器
注:使用频繁的事件委托实际上也是利用了事件冒泡。spa
仍是相同的DOM结构为例:设计
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="main"> <div class="btn-wrap"> <button id="btn">点击</button> </div> <div> <script type="text/javascript"> var btn=document.querySelector("#btn"), btnWrap=document.querySelector(".btn-wrap"), main=document.querySelector(".main"), body=document.querySelector("body"), html=document.querySelector("html"); btn.addEventListener("click",function(){ console.log("你点击了ID为btn的button元素!"); },false); btnWrap.addEventListener("click",function(){ console.log("你点击了class为btn-wrap的DIV元素!"); },false); main.addEventListener("click",function(){ console.log("你点击了class为main的DIV元素!"); },false); body.addEventListener("click",function(){ console.log("你点击了body元素!"); },false); html.addEventListener("click",function(){ console.log("你点击了html元素!"); },false); document.addEventListener("click",function(){ console.log("你点击了document对象!"); },false); </script> </body> </html>
若是咱们点击btn
,那么这个click事件的传播顺序以下:code
也就是,click事件首先在btn
元素上触发,而这个元素就是咱们单击的元素,而后click事件沿DOM树向上传播,在每一级的节点都会发生,直至传播到document对象。
全部现代浏览器都支持事件冒泡。htm
事件捕获,即事件从不太肯定的节点接收,而后向下传播到最具体的节点,事件捕获的用意在于在事件到达预期目标以前捕获它。DOM2级事件
规定addEventListener
方法的第三个参数设为true
,表示事件在捕获阶段触发。
仍是相同的DOM结构为例:
将参数改成true
对象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="main"> <div class="btn-wrap"> <button id="btn">点击</button> </div> <div> <script type="text/javascript"> var btn=document.querySelector("#btn"), btnWrap=document.querySelector(".btn-wrap"), main=document.querySelector(".main"), body=document.querySelector("body"), html=document.querySelector("html"); btn.addEventListener("click",function(){ console.log("你点击了ID为btn的button元素!"); },true); btnWrap.addEventListener("click",function(){ console.log("你点击了class为btn-wrap的DIV元素!"); },true); main.addEventListener("click",function(){ console.log("你点击了class为main的DIV元素!"); },true); body.addEventListener("click",function(){ console.log("你点击了body元素!"); },true); html.addEventListener("click",function(){ console.log("你点击了html元素!"); },true); document.addEventListener("click",function(){ console.log("你点击了document对象!"); },true); </script> </body> </html>
若是咱们点击btn
,那么这个click事件的传播顺序以下:事件
在事件捕获过程当中,document对象首先接收到click事件,而后事件沿着DOM树依次向下传播。
目前支持事件捕获流的浏览器有:IE9,Safari,Chrome,Opera,Firefox。
因为老版本浏览器不支持事件捕获,建议你们更多的是用事件冒泡,在有特殊须要时再使用事件捕获。
根据DOM2级事件
规定,事件流应该包括三个阶段,事件捕获阶段,处于目标阶段和事件冒泡阶段。
仍是相同的DOM结构为例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="main"> <div class="btn-wrap"> <button id="btn">点击</button> </div> <div> <script type="text/javascript"> var btn=document.querySelector("#btn"), btnWrap=document.querySelector(".btn-wrap"), main=document.querySelector(".main"), body=document.querySelector("body"), html=document.querySelector("html"); //冒泡 btn.addEventListener("click",function(){ console.log("你点击了ID为btn的button元素!"); },false); btnWrap.addEventListener("click",function(){ console.log("你点击了class为btn-wrap的DIV元素!"); },false); main.addEventListener("click",function(){ console.log("你点击了class为main的DIV元素!"); },false); body.addEventListener("click",function(){ console.log("你点击了body元素!"); },false); html.addEventListener("click",function(){ console.log("你点击了html元素!"); },false); document.addEventListener("click",function(){ console.log("你点击了document对象!"); },false); //捕获 btn.addEventListener("click",function(){ console.log("你点击了ID为btn的button元素!"); },true); btnWrap.addEventListener("click",function(){ console.log("你点击了class为btn-wrap的DIV元素!"); },true); main.addEventListener("click",function(){ console.log("你点击了class为main的DIV元素!"); },true); body.addEventListener("click",function(){ console.log("你点击了body元素!"); },true); html.addEventListener("click",function(){ console.log("你点击了html元素!"); },true); document.addEventListener("click",function(){ console.log("你点击了document对象!"); },true); </script> </body> </html>
若是咱们点击btn
,那么这个click事件的传播顺序以下:
在DOM事件流中,实际的目标btn
不会接收到事件。这意味着在捕获阶段,事件从document到btn-wrap
就中止了,下一阶段是“处于目标”阶段,因而事件在btn
上发生,而后冒泡阶段发生,事件又传播回文档。
注:多数支持DOM事件流的浏览器都实现了一种特定行为,即便
DOM2级事件
规范明确要求捕获阶段不会涉及目标阶段,IE9,Safari,Chrome,Firefox,Opera9.5及更高版本都会在事件捕获阶段触发事件对象上的事件,这也是上图btn
被触发两次的缘由。
IE9,Safari,Chrome,Firefox,Opera都支持DOM事件流,IE8及更早版本不支持DOM事件流。
本文知识点大多来自《JavaScript高级程序设计》一书,博主在这里也是作一次总结,巩固一下相关知识,同时也但愿没接触过事件流的童鞋们,有一个大概的概念。