了解捕获与冒泡
通过一个例子更好的了解吧
- 代码-HTML
- 即.爷爷>.爸爸>.儿子
- 给三个div分别添加事件监听 fnYe / fnBa / fnEr 点击谁监听谁
- 针对上面代码提问:
- 1点击了谁? 点击文字,算不算点击儿子?
点击文字,算不算点击爸爸?
点击文字,算不算点击爷爷?
-答案:都算
- 2. 调用顺序是怎样的?
点击文字,最先调用fnYe /fnBa / fnEr中的哪一个函数?
-答案:都行,看浏览器怎么实现的。
IE5认为先调 fnEr,网景认为先调fnYe,然后掐上了,最后闹到了W3C
和事佬W3C
2002年,W3C发布标准 文档名为DOM Level 2 Events Specification
规定浏览器应该同时支持两种调用顺序
首先按爷爷=>爸爸=>儿子顺序看有没有函数监听
然后按儿子=>爸爸=>爷爷顺序看有没有函数监听
有监听函数就调用,并提供事件信息,没有就跳过
- 术语: 从外向内找监听函数,叫做事件捕捉;
从内向外找监听函数,叫做事件冒泡;
-
捕获:当用户点击按钮,浏览器会从 window 从上向下遍历至用户点击的按钮,逐个触发事件处理函数。
-
冒泡:浏览器从用户点击的按钮从下往上遍历至 window,逐个触发事件处理函数。
-
W3C 事件模型/事件机制:对每个事件先捕获再冒泡
-
DOM事件机制图示:
W3C事件模型
- 事件绑定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 ,并提供事件信息;
- 你可以选择把fn放在哪边
- 代码示例:
- 简化后的代码:js.jirengu.com/luyetuxaba/…
- 代码图解:
小结
有两个疑问:
-
儿子被点击了,算不算点击爸爸? 算。
-
那么先调用爸爸的函数还是先调用儿子的函数?
不确定:IE先调用儿子,firefox就先调用爸爸,最终W3C说我两个都支持,先从老子到儿子,再从儿子到老子,这下你们满意了吧。
捕获与冒泡
捕获说先调用爸爸的监听函数,再调用儿子的监听函数;
冒泡说先调用儿子的监听函数,再调用爸爸的监听函数;
W3C事件模型
先捕获(先爸爸=>儿子) 再冒泡?(再儿子=>爸爸)(可以阻止冒泡)
注意 e 对象被传给所有监听函数
事件结束后, e 对象就不存在了
一个特例
- 背景 只有一个div被监听(不考虑父子同时被监听)
fn 分别在捕获阶段和冒泡阶段监听click事件
用户点击的元素就是开发者监听的
- 代码
- 请问: f1先执行还是f2先执行?
如果把两行调换位置后,请问哪个先执行?
错误答案:f2先执行
正确答案:谁先监听谁先执行,没有父子
总结:这是一个特例
取消冒泡
- 捕获不可取消,但冒泡可以 e.stopPropagation()可中断冒泡,浏览器不再向上走;
通俗来说:有人打我,我自己解决,别告诉我爸爸,一般用于封装某些独立的组件;
- 所有冒泡皆可取消,默认动作有的可以取消有的不能取消 MDN搜索scroll event,看到Bubbles和 Cancelable
Bubbles的意思是该事件是否冒泡,所有冒泡都可取消
Cancelable 是用来取消(也可以说阻止)默认动作的
Cancelable与冒泡无关
推荐看MDN英文版,中文版内容不全