简述js事件传播流程

一、概述

事件流:事件流描述的是从页面中接收事件的顺序。

DOM事件流传播的三个过程:

事件捕获阶段 ——》 处于目标阶段 ——》 事件冒泡阶段。

事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的元素

事件捕获:不太具体的节点更早接收事件,而最具体的元素最后接收事件,和事件冒泡相反

事件流示意

支持W3C标准的浏览器在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。而不兼容W3C的浏览器(IE)用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。

二、示例

假设一个元素div,它有一个下级元素p。

元素


这两个元素都绑定了click事件,如果用户点击了p,它在div和p上都触发了click事件,那这两个事件处理程序哪个先执行呢?事件顺序是什么?

事件捕获

当你使用事件捕获时,父级元素先触发,子级元素后触发,即div先触发,p后触发。

事件冒泡

当你使用事件冒泡时,子级元素先触发,父级元素后触发,即p先触发,div后触发。

W3C模型

W3C模型是将两者进行中和,在W3C模型中,任何事件发生时,先从顶层开始进行事件捕获,直到事件触发到达了事件源元素。然后,再从事件源往上进行事件冒泡,直到到达document。

【注】:当两个元素有包含关系并且事件相同时才会触发冒泡和捕获机制

另外:

1)、尽管“DOM2级事件”,即addEventListener(event,fn,useCapture)方法,标准规范明确规定事件捕获阶段不会涉及事件目标,但是在IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。所以结果就是有两次机会在目标对象上面操作事件。

2)、然而并非所有的事件都会经过冒泡阶段 。所有的事件都要经过捕获阶段和处于目标阶段,但是有些事件会跳过冒泡阶段:如,获得输入焦点的focus事件和失去输入焦点的blur事件。

三、阻止事件流

为何阻止事件流:

如我们点击p标签时希望只弹出1,但是点p的时候页会触发div上的点击事件弹出2,这是我们不想要的效果,所以就需要阻止事件流

阻止冒泡

document.getElementsByTagName("p").addEventListener("click",function(event){

console.log("阻止冒泡");   

event.stopPropagation();

},false);

另外:

event.cancelBubble=true;  IE8以下版本浏览器支持的阻止事件冒泡方法

上面的event.stopPropagation();是其他浏览器支持的阻止事件冒泡方法

阻止捕获

DOM3级新增事件stopImmediatePropagation()方法来阻止事件捕获,另外此方法还可以阻止事件冒泡

document.getElementsByTagName("p").addEventListener("click",function(){    

console.log("阻止捕获");    

event.stopImmediatePropagation();

},true); 

stopImmediatePropagation() 和 stopPropagation()的区别在哪儿呢?

后者只会阻止冒泡或者是捕获。 但是前者除此之外还会阻止该元素的其他事件发生,但是后者就不会阻止其他事件的发生。

注意:在DOM事件流中,实际的目标在捕获阶段不会接收到事件,下一个阶段是处于目标阶段,这时事件被触发,最后进入事件冒泡阶段。我们认为处于目标阶段是事件冒泡阶段的一部分。


四、两种事件流模型

1、所有现代浏览器都支持事件冒泡,但在具体实现中略有差别:

IE5.5及更早版本中事件冒泡会跳过元素(从body直接跳到document)。

IE9、Firefox、Chrome、和Safari则将事件一直冒泡到window对象。

2、IE9、Firefox、Chrome、Opera、和Safari都支持事件捕获。尽管DOM标准要求事件应该从document对象开始传播,但这些浏览器都是从window对象开始捕获事件的。

3、由于老版本浏览器不支持,很少有人使用事件捕获。建议使用事件冒泡


五、事件代理

传统的事件处理中,需要为每个元素添加事件处理器。js事件代理则是一种简单有效的技巧,通过它可以把事件处理器添加到一个父级元素上,从而避免把事件处理器添加到多个子级元素上。

target、this、currentTarget的区别

先诉重点理论:

1. target:触发事件的某个具体对象,只会出现在事件流的目标阶段(谁触发谁命中,所以肯定是目标阶段)

2. currentTarget:绑定事件的对象,恒等于this,可能出现在事件流的任意一个阶段中

3. 通常情况下terget和currentTarget是一致的,我们只要使用terget即可,但有一种情况必须区分这三者的关系,那就是在父子嵌套的关系中,父元素绑定了事件,单击了子元素(根据事件流,在不阻止事件流的前提下他会传递至父元素,导致父元素的事件处理函数执行),这时候currentTarget指向的是父元素,因为他是绑定事件的对象,而target指向了子元素,因为他是触发事件的那个具体对象,如下代码和截图所示:

 

one.addEventListener('click',function(e){

    console.log(e.target);  //three

    console.log(e.currentTarget);  //one

},false);


target:获得触发事件的标签,currentTarget:得到绑定事件的标签

你可能感兴趣的:(简述js事件传播流程)