欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Javascript中事件,事件流以及阻止事件冒泡的详解

程序员文章站 2022-05-06 09:11:01
...

1.什么事件?什么是事件流 ?事件流的出现?

一.什么是事件?
事件是文档或者浏览器窗口中发生的,特定的交互瞬间。

  事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字。
  事件是javaScript和DOM之间交互的桥梁。你若触发,我便执行——事件发生,调用它的处理函数执行相应的   JavaScript代码给出响应。典型的例子有:页面加载完毕触发load事件;用户单击元素,触发click事件

事件流:
通过使用JavaScript,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应
事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流。
事件流就是描述了页面中接受事件的顺序,在浏览器发展的初期,两大浏览器厂商IE和Netscape互掐,出现了一个坑爹的情况,那就是他们对事件流的解释出现了两中截然相反的定义。也就是我们所熟悉的:IE的事件冒泡,Netscape的事件捕获。对于IE浏览器和chrome,火狐,微软浏览器来说,兼容性性要处理,尤其是对IE来说,对其兼容性有一些特别的处理。事件流描述的是从页面中接收事件的顺序。
DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。
二.事件的传播

关于事件的传播网景公司和微软公司有不同的理解,

微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。

网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后在向内传播给后代元素

三.事件传播的阶段(DOM2级事件)
1.捕获型阶段:
事件捕获即事件最早由不太具体的节点接收,而最具体的节点最后接收到事件。点击text部分时,先由window接收,然后逐级传播至text元素;即由最不特定的事件目标到最特定的事件目标,DOM的根到叶子。
2.目标阶段
当事件到达目标节点时,事件就进入了目标阶段。事件在目标节点上被触发,然后逆向回流,知道传播到最外层的文档节点。对于多层嵌套的节点,鼠标和指针事件经常会被定位到最里层的元素上。假设,你在一个div元素上设置了click的监听函数,而用户点击在了这个div元素内部的p元素上,那么p元素就是这个时间的目标元素。事件冒泡让我们可以在这个div或者更上层的元素上监听click事件,并且时间传播过程中触发回调函数。
3.冒泡型阶段
事件冒泡即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的节点(文档)。当点击text部分时,先由text处的元素接收,然后逐级传播至window,即由最特定的事件目标到最不特定的事件目标,DOM的叶子到根。
注:对于捕获型阶段和冒泡型阶段中的第三个参数是布尔值类型:(true/false),默认是false:
在捕获阶段用事件处理程序(true):最早由不太具体的节点接收,而最具体的节点最后接收到事件;
在冒泡阶段用事件处理程序(false):最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的节点(文档);

true的触发顺序总在false前面;如果是多个false:内层到外层;多个true:外层到内层;

2.Javascript事件处理程序的3种方式
产生了事件,我们就要去处理他,Javascript事件处理程序主要有3种方式:

一.HTML事件处理程序:

即我们直接在HTML代码中添加事件处理程序,如下面这段代码:
Javascript中事件,事件流以及阻止事件冒泡的详解
从上面的代码中我们可以看出,事件处理是直接嵌套在元素里头的,这样有一个毛病:就是html代码和js的耦合性太强,如果哪一天想要改变js中showmsg,那么不但要再js中修改,还需要到html中修改,一两处的修改我们能接受,但是当你的代码达到万行级别的时候,修改起来就需要劳民伤财了,所以,这个方式我们并不推荐使用。

二:DOM0级事件处理程序:(普通事件)

即为指定对象添加事件处理,看下面的一段代码:
Javascript中事件,事件流以及阻止事件冒泡的详解
从上面的代码中,我们能看出,相对于HTML事件处理程序,DOM0级事件,html代码和js代码的耦合性已经大大降低。但是,聪明的程序员还是不太满足,期望寻找更简便的处理方式,下面来看第三种处理方法。
对于普通事件和DOM二级事件的区别:普通事件一般是多个相同的事件并且只会执行最后一个事件,且执行一次,前面的事件会被后面的覆盖,只支持冒泡,不支持捕获。DOM二级事件可以同时执行多个相同的事件,对于冒泡,捕获都支持。
注:普通事件的移除事件的方法:例如:oBox.onclick = null;

三:DOM2级事件处理程序:
DOM2也是对特定的对象添加事件处理程序,但是主要涉及到两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和 removeEventListener()。它们都接收三个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值(是否在捕获阶段处理事件),看下面的一段代码:
Javascript中事件,事件流以及阻止事件冒泡的详解
这里我们可以看到,在添加删除事件处理的时候,最后一种方法更直接,也最简便。但是马海祥提醒大家需要注意的是,在删除事件处理的时候,传入的参数一定要跟之前的参数一致,否则删除会失效!
注:冒泡型和捕获型事件对于相同事件绑定和解除,需要用***共同函数***;绑定和接触事件的没有“on”,即“onclick”写出“click”;
addEventListener()和 removeEventListener()用于事件监听;不l能移除匿名函数;通过冒泡型添加的只能通过捕获型来移除。

3.IE浏览器事件的处理:

一. IE事件处理程序也对应有两个方法:attachEvent()添加事件,detachEvent()删除事件,这两个方法接收相同的两个参数:事件处理程序名称与事处理函数。这里为什么没有布尔值呢?因为ie8以及更早的版本只支持事件冒泡,所以最后一个参数默认的相当于false来处理!(支持IE事件处理程序的浏览器有IE,opera)。

二 事件对象是用来记录一些事件发生时的相关信息的对象,但事件对象只有事件发生时才会产生,并且只能是事件处理函数内部访问,在所有事件处理函数运行结束后,事件对象就被销毁!

三:IE的事件监听器:attachEvent(事件名,处理函数),detachEvent(事件名,处理函数);注:事件名带“on”,(在IE下必须加on;在其他浏览器下不需要加)

4.事件代理(event delegation):

一:事件代理的诞生:
假如不停的删除或添加li,则function()也要不停的更改操作,易出错,因此推荐使用事件代理。

在传统的事件处理中,你按照需要为每一个元素添加或者是删除事件处理器。然而,事件处理器将有可能导致内存泄露或者是性能下降——你用得越多这种风险就越大。JavaScript事件代理则是一种简单的技巧,通过它你可以把事件处理器添加到一个父级元素上,这样就避免了把事件处理器添加到多个子级元素上。
二:事件代理机制(利用事件冒泡的原理):
事件代理用到了两个在JavaSciprt事件中两个特性:事件冒泡以及目标元素。使用事件代理,我们可以把事件处理器添加到一个元素上,等待一个事件从它的子级元素里冒泡上来,并且可以得知这个事件是从哪个元素开始的。
即用到的原理是:就是事件和目标元素,把事件处理器添加到子元素上,等到子元素事件冒泡,并且父元素通过target(IE为srcElement)判断是哪个子元素,从而做相应处理。
总结一下事件代理的好处:
将多个事件处理器减少到一个,因为事件处理器要驻留内存,这样就提高了性能。想象如果有一个100行的表格,对比传统的为每个单元格绑定事件处理器的方式和事件代理(即table上添加一个事件处理器),不难得出结论,事件代理确实避免了一些潜在的风险,提高了性能。
DOM更新无需重新绑定事件处理器,因为事件代理对不同子元素可采用不同处理方法。如果新增其他子元素(a,span,div等),直接修改事件代理的事件处理函数即可,不需要重新绑定处理器,不需要再次循环遍历。

5.阻止事件的传播:

一:什么是JS事件冒泡?

在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被**),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。

二:如何来阻止Jquery事件冒泡?
可以通过小例子来看:
Javascript中事件,事件流以及阻止事件冒泡的详解
比如上面这个页面,
分为三层:divOne是第外层,divTwo中间层,hr_three是最里层;
他们都有各自的click事件,最里层a标签还有href属性。
运行页面,点击“点击我”,会依次弹出:我是最里层---->我是中间层---->我是最外层
---->然后再链接到百度.
这就是事件冒泡,本来我只点击ID为hr_three的标签,但是确执行了三个alert操作。
事件冒泡过程(以标签ID表示):hr_three----> divTwo----> divOne 。从最里层冒泡到最外层。
如何阻止?
Javascript中事件,事件流以及阻止事件冒泡的详解
再点击“点击我”,会弹出:我是最里层,然后链接到百度

2.return false;
如果头部加入的是以下代码:
Javascript中事件,事件流以及阻止事件冒泡的详解
再点击“点击我”,会弹出:我是最里层,但不会执行链接到百度页面
由此可以看出:

1.event.stopPropagation();

事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)

2.return false;

事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)
还有一种有冒泡有关的:

3.event.preventDefault();

如果把它放在头部A标签的click事件中,点击“点击我”。

会发现它依次弹出:我是最里层---->我是中间层---->我是最外层,但最后却没有跳转到百度

它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接跳转)