DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。javascript
事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,若是父元素经过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。html
事件冒泡(dubbed bubbling):与事件捕获偏偏相反,事件冒泡顺序是由内到外进行事件传播,直到根节点。java
不管是事件捕获仍是事件冒泡,它们都有一个共同的行为,就是事件传播,它就像一跟引线,只有经过引线才能将绑在引线上的鞭炮(事件监听器)引爆,试想一下,若是引线不导火了,那鞭炮就只有一响了!!!浏览器
dom标准事件流的触发的前后顺序为:先捕获再冒泡,即当触发dom事件时,会先进行事件捕获,捕获到事件源以后经过事件传播进行事件冒泡。不一样的浏览器对此有着不一样的实现,IE10及如下不支持捕获型事件,因此就少了一个事件捕获阶段,IE十一、Chrome 、Firefox、Safari等浏览器则同时存在。dom
说到事件冒泡与捕获就不得不提一下两个用于事件绑定的方法addEventListener、attachEvent。固然还有其它的事件绑定的方式这里不作介绍。 函数
addEventListener(event, listener, useCapture) ui
·参数定义:event---(事件名称,如click,不带on),listener---事件监听函数,useCapture---是否采用事件捕获进行事件捕捉,spa
默认为false,即采用事件冒泡方式code
addEventListener在 IE十一、Chrome 、Firefox、Safari等浏览器都获得支持。htm
attachEvent(event,listener)
·参数定义:event---(事件名称,如onclick,带on),listener---事件监听函数。
attachEvent主要用于IE浏览器,而且仅在IE10及如下才支持,IE11已经废了这个方法了(微软仍是挺识趣的,慢慢向标准靠拢)。
说了一箩筐定义,下面就用上面这两个方法经过栗子来解释一下事件捕获与事件冒泡的具体表现行为差别。
事件冒泡
栗1:
<html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>js事件机制</title> <style> #parent{ width: 200px; height:200px; text-align: center; line-height: 3; background: green; } #child{ width: 100px; height: 100px; margin: 0 auto; background: orange; } </style> </head> <body> <div id="parent"> 父元素 <div id="child"> 子元素 </div> </div> <script type="text/javascript"> var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.body.addEventListener("click",function(e){ console.log("click-body"); },false); parent.addEventListener("click",function(e){ console.log("click-parent"); },false); child.addEventListener("click",function(e){ console.log("click-child"); },false); </script> </body> </html>
经过"addEventListener"方法,采用事件冒泡方式给dom元素注册click事件,点击子元素会发生什么呢?若是你对事件冒泡有必定了解的话那你确定知道上面的代码会输出的顺序,没错,以下图所示:
事件触发顺序是由内到外的,这就是事件冒泡,虽然只点击子元素,可是它的父元素也会触发相应的事件,其实这是合理的,由于子元素在父元素里面,点击子元素也就至关于变相的点击了父元素,这样理解对吧?
这里有同窗可能要问了,若是点击子元素不想触发父元素的事件怎么办?确定能够的,那就是中止事件传播---event.stopPropagation();
修改栗1的代码,在子元素的监听函数中加入中止事件传播的操做,栗2
child.addEventListener("click",function(e){ console.log("click-child"); e.stopPropagation(); },false);
在点击子元素的时候就只弹出了子元素那条信息,父元素的事件没有触发,由于事件已经中止传播了,冒泡阶段也就中止了。
事件冒泡差很少就讲述完了,别急,捕获还没说呢!
事件捕获
栗3,修改栗子1中的代码,给parent元素注册一个捕获事件,以下
var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.body.addEventListener("click",function(e){ console.log("click-body"); },false); parent.addEventListener("click",function(e){ console.log("click-parent---事件传播"); },false);
//新增事件捕获事件代码 parent.addEventListener("click",function(e){ console.log("click-parent--事件捕获"); },true); child.addEventListener("click",function(e){ console.log("click-child"); },false);
若是你看明白了我前面说的那些,你就知道这个栗子的输出顺序了。
父元素经过事件捕获的方式注册了click事件,因此在事件捕获阶段就会触发,而后到了目标阶段,即事件源,以后进行事件传播,parent同时也用冒泡方式注册了click事件,因此这里会触发冒泡事件,最后到根节点。这就是整个事件流程。
上面介绍了事件冒泡、事件捕获、事件传播,下面讲一下若是经过以上三个知识点进行事件委托
委托在JQuery中已经获得了实现,即经过$(selector).on(event,childSelector,data,function,map)实现委托,通常用于动态生成的元素,固然JQuery也是经过原声的js去实现的,下面举一个简单的栗子,经过js实现经过parent元素给child元素注册click事件
var parent = document.getElementById("parent"); var child = document.getElementById("child"); parent.onclick = function(e){ if(e.target.id == "child"){ console.log("您点击了child元素") } }
虽然没有直接只child元素注册click事件,但是点击child元素时却弹出了提示信息。
到这里是否是对js的事件机制有必定的了解了呢?感受有帮助的话就看看下面的小黄脸,你懂得哦!
若有错误,欢迎指正
若有问题,欢迎提问