浏览器-事件流的总结和理解(捕获阶段 目标阶段 冒泡阶段解析)

一 DOM事件流

百度百科,对于DOM事件流的解释:DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素节点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。

 

 

 

 

 

当有事件触发时,从DOM的根节点开始,向内传递,这一过程可以理解成①②③④的捕获阶段;

如果下图代码中的d节点被触发,事件整个传递到达目标阶段,该阶段结束后,事件会向上传递,一过程按照水底的气泡一样向上漂 ,称之为的⑤⑥⑦⑧ 冒泡阶段;

javaScript事件的三个阶段:捕获阶段 目标阶段 冒泡阶段

捕获阶段 概念:

事件从根节点流向目标节点,途中流经各个DOM节点,在各个节点上触发捕获事件,直到达到目标节点。

目标阶段 概念:

事件到达目标节点时,就到了目标阶段,事件在目标节点上被触发

冒泡阶段 概念:

事件在目标节点上触发后,不会终止,一层层向上冒,回溯到根节点

    <div id="a">
      <div id="b">
        <div id="c">
          <div id="d">点击这里</div>
        </div>
      </div>
    </div>

 

二 捕获事件流

捕获事件流可以在支持W3C 标准的浏览器中使用addEventListener处理,在菜鸟教程:addEventListener 中在线体验.

希望注册在DOM元素上的事件处理程序在捕获阶段还是在冒泡阶段触发,取决于 addEventListener() 方法的第三个参数为 true 还是 false ,addEventListener的第三个参数是一个布尔类型
1、第三个参数是false:事件从里到外执行,这种效果叫事件冒泡
2、第三个参数是true:事件从里到外执行,执行顺序颠倒过来了,这种效果叫做事件捕获。

第一阶段:捕获阶段 
第二阶段:目标阶段(执行当前点击的元素) 
第三阶段:冒泡阶段

 

该函数有三个参数:

  1. 事件名
  2. 触发执行函数
  3. 冒泡阶段还是捕获阶段执行,默认是在冒泡阶段执行
    <div id="a">
      <div id="b">
        <div id="c">
          <div id="d">点击这里</div>
        </div>
      </div>
    </div>
const a = document.getElementById('a')
const b = document.getElementById('b')
const c = document.getElementById('c')
const d = document.getElementById('d')
a.addEventListener('click', (e) => {
  const {
    target,
    currentTarget
  } = e
  console.log(`target是${target.id}`)
  console.log(`currentTarget是${currentTarget.id}`)
})
b.addEventListener('click', (e) => {
  const {
    target,
    currentTarget
  } = e
  console.log(`target是${target.id}`)
  console.log(`currentTarget是${currentTarget.id}`)
})
c.addEventListener('click', (e) => {
  const {
    target,
    currentTarget
  } = e
  console.log(`target是${target.id}`)
  console.log(`currentTarget是${currentTarget.id}`)
})
d.addEventListener('click', (e) => {
  const {
    target,
    currentTarget
  } = e
  console.log(`target是${target.id}`)
  console.log(`currentTarget是${currentTarget.id}`)
})

第三个参数不设置默认冒泡顺序,当触发d时呈现的结果如下

target是d currentTarget是d
target是d currentTarget是c
target是d currentTarget是b
target是d currentTarget是a
const a = document.getElementById('a')
const b = document.getElementById('b')
const c = document.getElementById('c')
const d = document.getElementById('d')
a.addEventListener('click', (e) => {
  const {
    target,
    currentTarget
  } = e
  console.log(`target是${target.id}`)
  console.log(`currentTarget是${currentTarget.id}`)
},true)
b.addEventListener('click', (e) => {
  const {
    target,
    currentTarget
  } = e
  console.log(`target是${target.id}`)
  console.log(`currentTarget是${currentTarget.id}`)
},true)
c.addEventListener('click', (e) => {
  const {
    target,
    currentTarget
  } = e
  console.log(`target是${target.id}`)
  console.log(`currentTarget是${currentTarget.id}`)
},true)
d.addEventListener('click', (e) => {
  const {
    target,
    currentTarget
  } = e
  console.log(`target是${target.id}`)
  console.log(`currentTarget是${currentTarget.id}`)
},true)

将addEventListener第三个参数设置为true,看看捕获阶段呢?

target是d currentTarget是a
target是d currentTarget是b
target是d currentTarget是c
target是d currentTarget是d

总结如下:

  1. e.target:触发事件的元素
  2. e.currentTarget:绑定事件的元素

三 事件委托

通过上面的例子,我们可以很清晰的发现,如果当前父级元素下有若干个子级元素,对父级做监听后,当我们通过addEventListener回调函数返回的e.tartget便能得到触发事件的元素。

    <div id='list'>
        <div id='item-1'>item-1</div>
        <div id='item-2'>item-2</div>
        <div id='item-3'>item-3</div>
        <div id='item-4'>item-4</div>
    </div>

通过给id为list的元素添加监听,在点击列表中的元素,便可实现事件委托,事件委托便是处理事件处理程序过多问题的一种解决方案;

四 阻止事件流

阻止事件流常用的两种种方式

e.stopPropagation():阻止目标元素的事件冒泡到父级元素;

e.preventDefault():取消一个目标元素的默认行为(例如:a链接,input标签的submit等);

 

posted @ 2022-06-07 11:44  八月正凉  阅读(497)  评论(0编辑  收藏  举报