捕获:当用户点击按钮,浏览器会从 window 从上向下遍历至用户点击的按钮,逐个触发事件处理函数。
冒泡:浏览器从用户点击的按钮从下往上遍历至 window,逐个触发事件处理函数。
W3C 事件模型/事件机制:对每个事件先捕获再冒泡

1、点击事件

  1. <div class= 爷爷>
  2. <div class= 爸爸>
  3. <div class= 儿子>
  4. 文字
  5. </div>
  6. </div>
  7. </div>

当给三个div分别添加事件监听 fnYe/fnBa/fnEr

问题:点击文字,最先调用哪个函数?
IE5 认为先调用fnEr
网景认为先调用fnYe

W3C 发布标准:规定浏览器应该同时支持两种调用顺序

首先按 爷爷=>爸爸=>儿子 顺序看有没有函数监听
然后按 儿子=>爸爸=>爷爷 顺序看有没有函数监听
有监听函数就调用,并提供事件信息,没有就跳过

像这种
从外向内找监听函数,叫事件捕获
从内向外找监听函数,叫事件冒泡

疑问:那岂不是fnYe/fnBa/fnEr都调用两次 ?非也
开发者自己选择把fnYe放在捕获阶段还是冒泡阶段
image.png

2、addEventListener

2.1 事件绑定API

image.png

2.2 如果 bool 不传或为 falsy

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

2.3 如果bool为true

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

2.4 你可以选择把fn放在哪边

image.png


一个点击事件样例:http://js.jirengu.com/bumow/1/edit?html,css,js,output
image.png

获取点击的状态,可以使用 currentTarget

  1. level1.addEventListener('click', (e)=>{
  2. const t = e.currentTarget
  3. setTimeout(()=>{
  4. //e会在事件结束之后自动消亡
  5. console.log(e)
  6. t.classList.remove('x')
  7. },n*1000)

在事件结束后,不推荐大家继续用 e,因为 e 会被浏览器悄悄改变,要用的话你应该提前把属性复制到自己的变量里,比如代码里的 const t = e.currentTarget 就是把 currentTarget 的引用复制到 t。

3、W3C事件模型

先捕获(先爸爸=>儿子)再冒泡(儿子=>爸爸)
注意e对象被传给所有监听函数
事件结束后,e对象就不存在啦
在事件结束后 e 会自动消亡,鼠标点击动作结束后 e 就消亡了

4、target V.S. currentTarget的区别

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

举例:
div>span{文字} 用户点击文字
e.target就是span
e.currentTarget就是div


5、一个特例

只有一个 div 被监听(不考虑父子同时被监听)
fn 分别在捕获阶段和冒泡阶段监听 click 事件
用户点击的元素就是开发者监听的
div.addEventListener(‘click’,f1)
div.addEventListener(‘click’,f2,true)
f1先执行还是f2先执行???把两行调换位置呢???
答案:谁先监听,谁先执行

  1. level7.addEventListener('click', ()=>{
  2. console.log(1)
  3. }) //冒泡
  4. level7.addEventListener('click', ()=>{
  5. console.log(2)
  6. },true) //捕获
  7. // 打印结果为 1,2
  8. level7.addEventListener('click', ()=>{
  9. console.log(2)
  10. },true) //捕获
  11. level7.addEventListener('click', ()=>{
  12. console.log(1)
  13. }) //冒泡
  14. //打印结果为 2,1

6、取消冒泡

捕获不可取消,但冒泡可以
e.stopPropagation() 可中断冒泡,浏览器不再向上走
一般用于封装某些独立的组件

7、不可阻止默认动作

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

8、小结

8.1 target和currentTarget

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

8.2 取消冒泡

e.stopPropagation()

8.3 事件的特性

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

8.4 如何禁用滚动

取消特定元素的wheel和touchstart的默认动作