JS 的事件机制
不是事件循环机制,是事件机制
通俗一点的概念是指的是DOM的事件绑定,触发吗?
事件的触发过程是怎么样的?什么是事件代理?
刚被问的时候有点懵,确认了下是不是问关于事件冒泡和捕获方面的知识。 我举了一个点击事件传递的例子,从root往事件触发处传播,遇到注册的捕获事件会触发,传播到事件触发处时触发注册的事件 从事件触发处往root传播,遇到注册的冒泡事件会触发
如果给一个目标节点(触发节点)同时注册冒泡和捕获事件,事件触发会按照注册的顺序执行
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
</head>
<body>
<div id="root">root
<p id="parent">parent
<span id="child">child</span>
</p>
</div>
<script>
let parentNode = document.getElementById('parent')
// 因为触发标签不同,导致输出顺序不同
// 点击parent会输出冒泡,捕获,因为目标节点按照绑定顺序输出
// 点击child会输出捕获,冒泡,因为非目标节点正常按照浏览器事件机制执行
parentNode.addEventListener(
'click',
event => {
console.log('冒泡')
},
false
)
parentNode.addEventListener(
'click',
event => {
console.log('捕获 ')
},
true
)
</script>
</body>
</html>
事件绑定(注册)
通常我们使用 addEventListener -MDN 注册事件
该函数的第三个参数可以是布尔值,也可以是对象
对于布尔值 useCapture
参数来说,默认值为 false
,useCapture
决定了注册的事件是捕获事件还是冒泡事件
对于对象参数来说,可以使用以下几个属性
capture
:布尔值,和useCapture
作用一样once
:布尔值,值为true
表示该回调只会调用一次,调用后会移除监听passive
:布尔值,表示永远不会调用preventDefault
如果我们希望事件只触发在目标上,可以使用 stopPropagation -MDN 来阻止事件的进一步传播
即 stopPropagation
用来阻止事件冒泡,也可以阻止捕获事件
stopImmediatePropagation -MDN 同样也能实现阻止事件 还能阻止该事件目标执行别的注册事件
js
dom.addEventListener(
'click',
event => {
event.stopImmediatePropagation()
console.log('冒泡')
},
false
)
// 点击 dom 只会执行上面的函数,该函数不会执行
dom.addEventListener(
'click',
event => {
console.log('捕获 ')
},
true
)
事件触发的过程
window
往事件触发处传播,遇到注册的捕获事件会触发- 传播到事件触发处时触发注册的事件
- 从事件触发处往
window
传播,遇到注册的冒泡事件会触发
js
// 以下会先打印冒泡然后是捕获
dom.addEventListener(
'click',
event => {
console.log('冒泡')
},
false // 默认值false, true则捕获阶段传播到该 EventTarget 时触发
)
dom.addEventListener(
'click',
event => {
console.log('捕获')
},
true
)
事件代理
如果一个节点中的子节点是动态(遍历)生成的,想给子节点注册事件可以注册到父节点上
html
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
let ul = document.querySelector('#ul')
ul.addEventListener('click', (event) => {
console.log(event.target);
})
</script>
事件代理的方式相较于直接给目标注册事件来说,有以下优点:
- 节省内存
- 不需要给子节点注销事件