您的位置:首页 > Web前端 > JavaScript

JavaScript冒泡捕获事件流详解

2017-03-13 13:36 666 查看
JavaScript事件由来已久,他们是js和html之间交互的桥梁,同时纵观整个事件响应得过程基本符合观察者模式,js订阅html中的事件是否发生,一旦发生即发布内容,js回调相应做出回应

在事件的发展史上,曾经有过一个非常有意思的分歧,浏览器发展初期,还是网景公司和微软争霸天下,当时他们都已经上线了事件机制,但这起中还存在一个他们深深困惑的事情,如click事件,当你原本想点击页面中的一个元素时,同时必定点击了html,body等元素,那么是算先点击了更深层的div等元素呢,还是更表层的html元素呢

网景公司采用事件捕获机制,即先点击最表层

微软公司采用事件冒泡机制,即先点击最深层

当年的两种著名说法促成了现在的统一标准,现在的DOM2中规定,事件流包括三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段,当然IE8以及之前的浏览器还是一如既往的只有冒泡事件。

首先发生事件捕获,可以在捕获的阶段进行截取事件,事件逐层深入,然后到达真正的目标,此时事件就发生了,最后进行冒泡,可以在这个阶段进行事件响应

事件注册时,主要存在事件类型,回调函数,或许还有事件流方式等要点,老一点的可能呈现形式就是DOM0级事件处理方式

elem.onclick = function(){}


DOM2级出现后,定义了addEventListener以及removeEventListener函数,主要优点是可以为某个元素添加多个同一种事件,另外还可以手动选择在什么阶段进行事件处理程序

elem.addEventListener('click', function(){}, false)


参数分别为,事件类型,事件处理程序,是否在捕获阶段进行事件处理程序,为了更好的兼容某些只有冒泡流的浏览器,我们大多时候都是省略最后一个参数,默认选择冒泡。

我们大概粗略整体性介绍完了事件,接下来就深入事件处理程序进入重点——事件对象,事件对象指当事件发生时产生的一个名为event的对象,里面储存着当前事件的信息,如事件类型,触发事件的目标元素,事件流的层次,事件进行到的阶段等等,其生命周期随事件结束而结束。

列一下重要的属性和方法

bubbles boolean 是否冒泡

stopPropagation function 取消事件进一步捕获或者冒泡(bubbles为true时可以调用)

cancelable boolean 是否可以取消事件的默认行为

preventDefault function 取消事件的默认行为(在cancelable为true时可以使用)

defaultPrevented boolean 是否已经调用preventDefault函数

currentTarget element 正在事件处理的元素

target element 事件目标,与楼上不相同,这是个不变值

type string 被处罚的事件的类型

detail integer 事件相关的细节信息

eventPhase integer 事件处理程序的阶段

stopImmediatePropagation function 取消事件的进一步捕获或者冒泡,同时阻断事件处理程序被调用

就在CSDN的markdown编辑页面,我截了个图,google56版event除原型外的所有参数,我们可以看到还是有很多的,其中每个都有着各式各样的用处,比如表示各种位置的,clientx(y),screenx(y),还有整个事件流经过的所有DOM元素的数组path等



可以看到这是一个冒泡,可以取消事件默认行为,目标为a.btn.btn-success的click事件。

让我们用上面的event属性来进行一个事件流整体捕获和冒泡拦截实现

document.getElementById('btn1').onclick =
e => {
console.log(e.eventPhase, e.target === e.currentTarget)
e.preventDefault()
e.stopPropagation()
}//2,true

document.body.addEventListener( 'click',
e => {console.log(e.eventPhase)}, true)//1

document.body.onclick =
e => console.log(e.eventPhase)
//3,没有stopPropagation才会有结果


上面的情境中,我们点击btn1后,首先在捕获阶段用第二个事件处理程序进行处理,然后到达目标元素btn1后,进入处于目标阶段phase为2,此时target和currentTarget是相同的,最后进入冒泡阶段,此时phase为3。

现在我们应该对事件流有了大概了解了,接下来我们将上面的代码在冒泡阶段实施的行为展开说说

没错,就是事件委托,事件委托利用了事件冒泡的性质,顾名思义,就是将多个子元素的事件响应委托给父元素进行统一管理响应,这在事件处理程序过多时十分有用。

总体来说,事件委托有以下几个优点

1.绑定在高层元素,几乎可以在页面任何生命周期中进行绑定。比如document无需等待页面load完毕就可以进行绑定,大大节省绑定事件消耗时间。

2.绑定事件程序运行时间短。因为其将多个事件绑定程序减少为一个或几个程序。

3.节省绑定事件的内存和性能消耗。每当事件处理程序与页面上的元素绑定后,他们之间就会建立起一个连接,连接数目少了内存消耗就少了,性能也就相应提升了

同时事件委托也有利于我们移除事件处理程序,在实际应用中,我们经常只添加而不移除,这样造成了极大的内存浪费,特别在DOM操作删除节点或者直接innerHTML操作后,DOM节点虽然删除了,但事件处理程序还处在内存中。

最后总结一下,事件处理程序是页面交互的窗口,支持着不同事件类型实现不同的行为,其内部实现符合观察者模式,是一种十分精妙的创造,另外事件发生的流程分为三部分,捕获、目标、冒泡,其中冒泡比较重要,我们经常会利用这个特性进行委托等。

事件处理程序依靠包含着全部事件信息的事件对象进行一系列行为,包括阻止默认行为,事件委托等,最后我们在使用事件的时候要特别注意移除不用的事件处理程序,节省内存,提高性能。

4000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息