事件与事件委托

115 阅读3分钟

事件与事件委托

对于一个点击事件来说,究竟是从外向内还是从内到外的进行事件的监听呢?

2002 年,W3C 发布标准

文档名为 DOM Level 2 Events Specification

规定浏览器应该同时支持两种调用顺序

  • 首先按爷爷=>爸爸=>儿子顺序看有没有函数监听
  • 然后按儿子=>爸爸=>爷爷顺序看有没有函数监听

有监听函数就调用,并提供事件信息,没有就跳过

术语

外向内找监听函数,叫事件捕获

内向外找监听函数,叫事件冒泡

疑问:那岂不是 fnYe / fnBa / fnEr 都调用两次?非也!

开发者自己选择把 fnYe 放在捕获阶段还是放在冒泡阶段

addEventListener

事件绑定 API

IE 5*:baba.attachEvent('onclick', fn) // 冒泡

网景:baba.addEventListener('click',fn) // 捕获

W3C:baba.addEventListener('click', fn, bool)

如果 bool 不传或为 falsy

  • 就让 fn 走冒泡,即当浏览器在冒泡阶段发现 baba 有 fn 监听函数,就会调用 fn,并提供事件信息

如果 booltrue

  • 就让 fn 走捕获,即当浏览器在捕获阶段发现 baba 有 fn 监听函数,就会调用 fn ,并提供事件信息

所有的运行都遵循着:先捕获,再冒泡

  • 先执行捕获的函数
  • 再执行冒泡的函数
  • 注意 e 对象被传给所有监听函数
  • 事件结束后,e 对象就不存在了

后面两个有更多的理解,之后再说

target v.s. currentTarget

区别

  • e.target - 用户操作的元素
  • e.currentTarget - 程序员监听的元素
  • thise.currentTarget,我个人不推荐使用它

举例

  • div > span{文字},用户点击文字
  • e.target 就是 span
  • e.currentTarget 就是 div

历史(现在不是这样了)

以前存在一个特例

背景

  • 只有一个 div 被监听(不考虑父子同时被监听)
  • fn 分别在捕获阶段和冒泡阶段监听 click 事件
  • 用户点击的元素就是开发者监听的

代码

  • div.addEventLisenter('click', f1)
  • div.addEventLisenter('click', f2, true)

请问,f1 先执行还是 f2 先执行?

  • 如果把两行调换位置后,请问哪个先执行?

错误答案:f2 先执行

  • 正确答案:谁先监听谁先执行

总结:这是一个特例

!!!但是这个2022年已经被修改了,遵循先捕获在冒泡

取消冒泡

  • 捕获不可取消,但冒泡可以
  • e.stopPropagation() 可中断冒泡,浏览器不再向上走

通俗来说:有人打我,我自己解决,别告诉我老子

一般用于封装某些独立的组件

不可阻止默认动作

有些事件不能阻止默认动作

MDN 搜索 scroll event,看到 Bubbles 和 Cancelable

  • Bubbles 的意思是该事件是否冒泡,所有冒泡都可取消
  • Cancelable 的意思是开发者是否可以阻止默认事件
  • Cancelable 与冒泡无关

scroll 事件不可阻止默认动作

  • 阻止 scroll 默认动作没用,因先有滚动才有滚动事件
  • 要阻止滚动,可阻止 wheeltouchstart 的默认动作
  • 注意你需要找准滚动条所在的元素
  • 但是滚动条还能用,可用 CSS 让滚动条 width: 0

CSS 也行

  • 使用 overflow: hidden 可以直接取消滚动条
  • 但此时 JS 依然可以修改 scrollTop

事件委托

比如说,我需要在以下div中对特定的button让事件冒泡

<div class=“div1”>
    <button class="b1">1</button>
    <button class="b2">2</button>
    <button class="b3">3</button>
</div>

可以封装一个函数,实现事件委托

on('click', '.div1', 'b1', fn)

把事件放在div上,然后当b1触发之后执行fn函数

优点

  1. 省监听数(节省内存)
  2. 可以监听动态元素

总结

  1. targetcurrentTarget

    一个是用户点击的,一个是开发者监听的

  1. 取消冒泡

    e.stopPropagation()

  1. 事件的特性

    Bubbles 表示是否冒泡

    Cancelable 表示是否支持开发者取消冒泡

  1. scroll 不支持取消冒泡、

    如何禁用滚动

    取消特定元素的 wheeltouchstart 的默认动作