DOM事件
DOM事件模型和事件流
DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。
(1)捕获阶段:事件从window对象自上而下向目标节点传播的阶段;
(2)目标阶段:真正的目标节点正在处理事件的阶段;
(3)冒泡阶段:事件从目标节点自下而上向window对象传播的阶段。
事件捕获和事件冒泡
-
从外向内找监听函数,叫事件捕获(爷爷=>爸爸=>儿子)
-
从内向外找监听函数,叫事件冒泡(儿子=>爸爸=>爷爷)
-
示意图
事件绑定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放在哪边
DOM事件捕获和冒泡的具体流程
-
捕获是从上到下,事件先从
window对象,然后再到document(对象),然后是html标签(通过document.documentElement获取html标签),然后是body标签(通过document.body获取body标签),然后按照普通的html结构一层一层往下传,最后到达目标元素。 -
而事件冒泡的流程刚好是事件捕获的逆过程。
代码
let n = 1
level1.addEventListener('click', (e)=>{
const t = e.currentTarget
setTimeout(()=>{
t.classList.remove('x')
}, n * 1000 )
n += 1
},true)
level1.addEventListener('click', (e)=>{
const t = e.currentTarget
setTimeout(()=>{
t.classList.add('x')
}, n * 1000 )
n += 1
})
...
W3C 事件模型
-
先捕获(先爸爸=>儿子)再冒泡(再儿子=>爸爸)
-
注意 e 对象被传给所有监听函数
-
事件结束后,e 对象就不存在了
target v.s. currentTarget
区别
-
e.target// 用户操作的元素 -
e.currentTarget// 程序员监听的元素 -
this 是 e.currentTarget,不推荐使用它
-
event.target指向引起触发事件的元素,而event.currentTarget则是事件绑定的元素,只有被点击的那个目标元素的event.target才会等于event.currentTarget。也就是说,event.currentTarget始终是监听事件者,而event.target是事件的真正发出者。
举例
-
div > span{文字},用户点击文字 -
e.target就是 span -
e.currentTarget就是 div
取消冒泡
-
捕获不可取消,但冒泡可以
-
e.stopPropagation()可中断冒泡,浏览器不再向上走 -
e.stopPropagation()方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行。
不可阻止默认动作
有些事件不能阻止默认动作
-
Bubbles 的意思是该事件是否冒泡,所有冒泡都可取消
-
Cancelable 的意思是开发者是否可以阻止默认事件
-
Cancelable 与冒泡无关
-
所有
冒泡皆可取消,默认动作有的可以取消有的不能取消 -
Cancelable 是用来取消(也可以说阻止)默认动作的
如何阻止滚动
scroll 事件不可阻止默认动作
-
阻止 scroll 默认动作没用,因先有滚动才有滚动事件
-
要阻止滚动,可阻止 wheel 和 touchstart 的默认动作
-
注意:需要找准滚动条所在的元素
-
滚动条还能用,可用 CSS 让滚动条 width: 0
event. preventDefault()
- 如果调用这个方法,默认事件行为将不再触发。
x.addEventListener('wheel',(e)={
e.preventDefault()
}) //阻止页面滚动
x.addEventListener('touchstart',(e)={
e.preventDefault
}) //阻止手机页面滚动
CSS 也行
-
使用 overflow: hidden 可以直接取消滚动条
-
但此时 JS 依然可以修改 scrollTop
总结:
target 和 currentTarget
- 一个是用户点击的,一个是开发者监听的
取消冒泡
e.stopPropagation()
事件的特性
-
Bubbles 表示是否冒泡
-
Cancelable 表示是否支持开发者取消冒泡
-
如 scroll 不支持取消冒泡
如何禁用滚动
- 取消特定元素的 wheel 和 touchstart 的默认动作
自定义事件
浏览器自带事件
-
一共100多种事件,可查询MDN
-
在自带事件之外,自定义一个事件
事件委托
优点
省监听数(内存)
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li
- 如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能;因此,比较好的方法就是把这个点击事件绑定到他的父层,也就是
ul上,然后在执行事件的时候再去匹配判断目标元素;
可以监听动态元素
- 事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的。
- Element.matches API 的基本使用方法: Element.matches(selectorString),selectorString 既是 CSS 那样的选择器规则。
JS支持事件吗
-
支持,也不支持。本节课讲的 DOM 事件不属于 JS 的功能,术语浏览器提供的 DOM 的功能
-
JS 只是调用了 DOM 提供的 addEventListener 而已