• Event flow


    考虑这么个例子:

    <div>
      <button id="btn">Click Me!</button>
    </div>
    

    哪怕一个web开发的初学者都会知道,当我们鼠标在button上点击时,会在button上触发一个click事件。但是:

    • button是div的一个子Node;从界面上来看,在button里点击相当于在div里点击;那click事件也会触发在div上吗?
    • 如果click事件也触发在div上,那它们会不会共用同一个事件对象?
    • 如果click事件也触发在div上,谁的事件会先发生?
    • click事件还会在哪些元素上面触发?
    • 等等...

    想解答上述问题,我们需要理解事件(Event)一个很重要的机制:事件流动(Event Flow)。

    事件流动

    DOM事件不单单只会在一个Element上触发,它还会流向其他Element。事件的流动通常会经历这么三个阶段:

    捕获阶段 -> 目标阶段 -> 冒泡阶段
    

    "eventPhase"

    “eventPhase”是“Event”下的一个属性,它指明当前event属于那一个阶段。
    “eventPhase”可能是一下其中一个值:

    • Event.NONE,0,没有事件需要处理
    • Event.CAPTURING_PHASE,1,捕获阶段
    • Event.AT_TARGET,2,目标阶段,事件对象到达事件目标上
    • Event.BUBBLING_PHASE,3,冒泡阶段

    下面我们详细讨论一下这三个阶段。

    捕获阶段(capture phase)

    捕获阶段的定义如下(w3c):

    The event object propagate through the target's ancestors from the defaultView to the target's parent.
    事件对象在事件目标的祖先中上到下顺向传播,从最顶层的defaultView到事件目标的(直系)父元素。

    捕获阶段发生在整个事件流动的开始。在这阶段里事件会从父(主干)到子(分支)由上往下传播,被元素一层层地捕获。
    文章开头的例子里面,捕获阶段的click事件会依次在document、body、div上触发:

    document    1
      v
    body    2
      v
    div    3
      v
    button
    

    一般我们没太大需要监听捕获阶段的事件;如果你确实希望这么做,需要将addEventListener的第三个参数设置为true:

    // 第三个参数设置是否为捕获阶段,默认为false
    element.addEventListener('click', function() {}, true)
    

    目标阶段(target phase)

    目标阶段的定义是(w3c):

    The event object arrive at the event object's event target.
    事件对象到达事件目标。

    例子里面,就是事件在button上触发的。addEventListener可以监听目标阶段的事件:

    element.addEventListener('click', function() {})
    

    如果事件是不可冒泡的,那整个事件流动会到此为止,不会发生下面的冒泡阶段。

    冒泡阶段(bubble phase)

    冒泡阶段的定义如下(w3c):

    The event object propagates through the target's ancestors in reverse order, starting with the target's parent and ending with the defaultView.
    事件对象会在事件目标的祖先元素里反向传播,由开始的父元素到最后的defaultView(document)。

    冒泡阶段发生在最后,这也是我们最为熟悉的一个阶段。在这阶段里事件会从子(分支)到父(主干)逆向传播,看起来像是一个水里的泡泡往上冒。
    例子里面,冒泡阶段的click事件会依次在div、body、document上触发:

    document    3
      ^
    body    2
      ^
    div    1
      ^
    button
    

    "bubbles"

    Event下的bubbles属性标明该事件是否为可冒泡的。一旦该值为false,则说明 evnet不可冒泡,那其流动也会在第二阶段“目标阶段”后就终止。


    总结

    若一个元素(div)是目标元素(button)的祖先,那事件对象会在该元素上触发两次:一次是捕获阶段(1)的,另一次是冒泡阶段(3)的。当事件对象在事件目标元素(button)上触发时,事件流动进入了目标阶段(2)。

    • 想监听捕获阶段的事件,可以这样:element.addEventListener('click', cb, true),将第三个参数设置为true。
    • 想监听冒泡阶段的事件,可以这样:element.addEventListener('click', cb,),不使用第三个参数或将其设置为false。
    • 而上述的任何一种监听方式都可以监听到目标阶段的事件。

    最后,你可以配合这个例子来确认一下你的理解。

          let divElement = document.querySelector('div')
          let btnElement = document.querySelector('button')
          
          document.body.addEventListener('click', event => {
            console.log('Body Click in Bubble Phase.')
            console.log('Event Phase: ' + event.eventPhase)
          })
          
          document.body.addEventListener('click', event => {
            console.log('Body Click in Capture Phase.')
            console.log('Event Phase: ' + event.eventPhase)
          }, true)
    
          divElement.addEventListener('click', event => {
            console.log('Div Click in Bubble Phase.')
            console.log('Event Phase: ' + event.eventPhase)
          })
          
          divElement.addEventListener('click', event => {
            console.log('Div Click in Capture Phase.')
            console.log('Event Phase: ' + event.eventPhase)
          }, true)
          
          btnElement.addEventListener('click', event => {
            console.log('Button Click in Target Phase.')
            console.log('Event Phase: ' + event.eventPhase)
          })
          
          btnElement.addEventListener('click', event => {
            console.log('Button Click in Target Phase.')
            console.log('Event Phase: ' + event.eventPhase)
          }, true)
    
    Body Click in Capture Phase.
    Event Phase: 1
    Div Click in Capture Phase.
    Event Phase: 1
    Button Click in Target Phase.
    Event Phase: 2
    Button Click in Target Phase.
    Event Phase: 2
    Div Click in Bubble Phase.
    Event Phase: 3
    Body Click in Bubble Phase.
    Event Phase: 3



    作者:butterandfly
    链接:https://www.jianshu.com/p/382895a4027d
    來源:简书

  • 相关阅读:
    AngularJS Insert Update Delete Using PHP MySQL
    Simple task manager application using AngularJS PHP MySQL
    AngularJS MySQL and Bootstrap Shopping List Tutorial
    Starting out with Node.js and AngularJS
    AngularJS CRUD Example with PHP, MySQL and Material Design
    How to install KVM on Fedora 22
    Fake_AP模式下的Easy-Creds浅析
    河南公务员写古文辞职信
    AI
    政协委员:最大愿望是让小学生步行上学
  • 原文地址:https://www.cnblogs.com/Yehudic/p/10139752.html
Copyright © 2020-2023  润新知