再探事件的三个阶段

个人原文连接:再探事件的三个阶段
偶然间看到一篇经典博客,文中有一个例子挺有意思,大概是:html

<div id="p">parent</div>
<script>
    var p = document.getElementById('p');
    p.addEventListener('click', function(e) {
        alert('parent节点冒泡')
    }, false);
    p.addEventListener('click', function(e) {
        alert('parent节点捕获')
    }, true);
</script>

问点击div时,事件触发的顺序是什么?chrome


根据事件的三个阶段,我最初推测应该是先触发捕获事件再触发冒泡事件,但实际结果倒是先弹出冒泡再弹出捕获。这是为何呢?
事情先要从 addEventListener() 方法提及,MDN文档中关于此方法有明确描述:浏览器

若是事件监听器刚好注册到了事件目标上,那么这个事件会处于“目标阶段”,而不是冒泡阶段或者捕获阶段。在目标阶段的事件会触发全部的监听器,而不在意这个监听器到底在注册时 useCapture 参数值是什么。数据结构

也就是说若是咱们直接单击目标,那么当事件被触发时,event target正处于第二阶段,这时全部的事件按照注册前后顺序触发,与是否设置第三个参数无关。dom


event 对象中有一个字段专门用于描述事件当前是处于哪一个阶段:eventPhasepost

  • 0:当前没有事件须要处理;动画

  • 1:捕获阶段,事件从window传递到目标;spa

  • 2:命中阶段,事件已经到达目标;操作系统

  • 3:冒泡阶段,事件从目标传达到最顶层的window的过程;设计

W3C标准中有一张图描述了这个过程:

其中提到的三个阶段是 capture phasetarget phasebubble phase,事件对象的传播是根据 propagation path 进行的。完整的例子以下:
codepen

我对事件的整个生命周期的各个阶段的了解实际上是很是有限的,我的推测以下:

  • 操做系统捕获事件(点击、触摸等);

  • 浏览器从操做系统那里得到事件的相关信息并生成事件对象;

  • 浏览器计算事件传播的路径;

  • 按照路径传播并触发相应节点上的事件;

  • 最后由浏览器销毁事件对象;

基于以上猜想,有几点不是很明白:

  1. 为何要设计成三个阶段?

    有些地方是讲的:由于历史缘由——N公司提倡捕获,M公司提倡冒泡,两个公司互不妥协,因而标准组织干脆兼容二者,让事件跑一个来回,假若不支持某个过程则静默出进入相关阶段就好。长此以往,你们都认了这个规则,可是实际上来讲让事件跑一个来回效率上确定是不高的,并且从个人理解来看只进行捕获或者冒泡也是合乎逻辑的。因此为何现代浏览器(好比chrome)要同时支持两种传播方式呢?

  2. 传播路径如何肯定?

    上文中说到事件在传播前,浏览器会先为其计算出传播路径,然而DOM树表面上看并非一棵查找二叉树,只是一种描述层级关系的树状数据结构。那么假设浏览器从操做系统拿到了事件的基本信息(点击位置,哪一个键位,发生时间等),浏览器怎么在这样的树状结构中查找出一条肯定的路径呢?遍历固然是能够的,可是这样效率是否过低?若是每一个元素都有一个独一无二的ID,对这个路径查找问题有帮助吗?

  3. 事件与其它过程如何交互?

    问题可能说的有点抽象,假设咱们在div元素上绑定了一个hover动画,那么当鼠标划过期须要发生两件事情:展现动画和触发mouseover事件。我以为合理的设计应该是先触发动画再触发事件,有两种可能性:

    • 浏览器在事件传播前触发动画,不管是捕获仍是冒泡,对动画触发前后没有影响;

    • 浏览器在在事件传播过程当中触发动画,那么动画触发顺序可能和采用捕获仍是冒泡有关系;


请不吝赐教。

相关文章
相关标签/搜索