JavaScript冒泡捕获事件流详解

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等

    event控制台截图

    可以看到这是一个冒泡,可以取消事件默认行为,目标为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节点虽然删除了,但事件处理程序还处在内存中。

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值