事件与事件委托
对于一个点击事件来说,究竟是从外向内还是从内到外的进行事件的监听呢?
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,并提供事件信息
如果 bool 为 true
- 就让 fn 走捕获,即当浏览器在捕获阶段发现 baba 有 fn 监听函数,就会调用 fn ,并提供事件信息
所有的运行都遵循着:先捕获,再冒泡。
- 先执行捕获的函数
- 再执行冒泡的函数
- 注意 e 对象被传给所有监听函数
- 事件结束后,e 对象就不存在了
后面两个有更多的理解,之后再说
target v.s. currentTarget
区别
- e.target - 用户操作的元素
- e.currentTarget - 程序员监听的元素
- this 是 e.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默认动作没用,因先有滚动才有滚动事件
- 要阻止滚动,可阻止
wheel和touchstart的默认动作
- 注意你需要找准滚动条所在的元素
- 但是滚动条还能用,可用
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函数
优点
- 省监听数(节省内存)
- 可以监听动态元素
总结
-
target 和 currentTarget
一个是用户点击的,一个是开发者监听的
-
取消冒泡
e.stopPropagation()
-
事件的特性
Bubbles 表示是否冒泡
Cancelable 表示是否支持开发者取消冒泡
-
如 scroll 不支持取消冒泡、
如何禁用滚动
取消特定元素的 wheel 和 touchstart 的默认动作