DOM 事件
DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播,这种传播分为三个阶段。
- 捕获阶段:事件从window对象自上而下向目标节点传播,所有经过的节点,都会触发对应的事件
- 目标阶段:目标节点处理事件
- 冒泡阶段:事件从目标节点自下而上向window对象传播,同样,所有经过的 节点,都会触发对应的事件
!
addEventListener
绑定事件对象.addEventListener(事件类型,回调函数,布尔值)
如:target.addEventListener('click',fn,true)
- 如果不传布尔值或为falsy值 -- fn就会走冒泡阶段,
- 如果布尔值为true -- fn 就会走捕获阶段
代码示例:点击target
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<style>
div{
border: 1px solid red;
padding: 10px;
}
</style>
</head>
<body>
<div class="parent">container
<div class="child">box
<div class="target">target</div>
</div>
</div>
</body>
<script>
const $ = s => document.querySelector(s)
$('.parent').addEventListener('click',function(e){
console.log('在捕获阶段,parent 开始处理')
},true)
$('.child').addEventListener('click',function(e){
console.log('在捕获阶段,child 开始处理')
},true)
$('.target').addEventListener('click',function(e){
console.log('在捕获阶段,target 开始处理')
},true)
$('.parent').addEventListener('click',function(e){
console.log('在冒泡阶段,parent 开始处理')
},false)
$('.child').addEventListener('click',function(e){
console.log('在冒泡阶段,child 开始处理')
},false)
$('.target').addEventListener('click',function(e){
console.log('在冒泡阶段,target 开始处理')
},false)
</script>
</html>
//
"在捕获阶段,parent 开始处理"
"在捕获阶段,child 开始处理"
"在捕获阶段,target 开始处理"
"在冒泡阶段,target 开始处理"
"在冒泡阶段,child 开始处理"
"在冒泡阶段,parent 开始处理"
阻止事件冒泡
e.stopPropagation()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<style>
div{
border: 1px solid red;
padding: 10px;
}
</style>
</head>
<body>
<div class="parent">container
<div class="child">box
<div class="target">target</div>
</div>
</div>
</body>
<script>
const $ = s => document.querySelector(s)
$('.parent').addEventListener('click',function(e){
console.log('在捕获阶段,parent 开始处理')
},true)
$('.child').addEventListener('click',function(e){
e.stopPropagation()
console.log('在捕获阶段,child 开始处理')
},true)
$('.target').addEventListener('click',function(e){
console.log('在捕获阶段,target 开始处理')
},true)
$('.parent').addEventListener('click',function(e){
console.log('在冒泡阶段,parent 开始处理')
},false)
$('.child').addEventListener('click',function(e){
console.log('在冒泡阶段,child 开始处理')
},false)
$('.target').addEventListener('click',function(e){
console.log('在冒泡阶段,target 开始处理')
},false)
</script>
</html>
//
"在捕获阶段,parent 开始处理"
"在捕获阶段,child 开始处理"
事件委托
事件委托又叫事件代理,由于冒泡阶段会从子节点向上传播到父节点,因此可以监听父节点来处理多个子节点的事件。
有时我们会遇到一些问题,比如:
- 你要给100个按钮做监听事件,咋办?
- 你要监听目前不存在的元素的事件,咋办?
这个时候,可以监听这些元素的祖先,等冒泡或事件触发时判断是不是我想要监听的元素即可。
假设有10个按钮
HTML
<!DOCTYPE>
<html>
<head>
<meta charset='UTF-8'>
<title>事件委托</title>
<head>
<body>
<div class='btn'>
<button>btn1</button>
<button>btn2</button>
<button>btn3</button>
<button>btn4</button>
<button>btn5</button>
<button>btn6</button>
<button>btn7</button>
<button>btn8</button>
<button>btn9</button>
<button>btn10</button>
</div>
<script>
</script>
</body>
<html>
JS
// 监听祖先元素
const btn = document.querySelector('.btn')
btn.addEventListener('click', (e) => {
const t = e.target
if (t.tagName.toLowerCase() === 'button') {
console.log('button被点击了');
console.log('被点击的button是' + t.textContent);
}
})
//
点击btn2
"button被点击了"
"被点击的button是btn2"
button一开始不存在
HTMl
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id=div1></div>
</body>
</html>
JS
setTimeout(()=>{
const button = document.createElement('button')
button.textContent = 'click'
div1.appendChild(button)
},1000)
div1.addEventListener('click',(e)=>{
const t = e.target
if(t.tagName.toLowerCase() === 'button'){
console.log('button 被 点击了')
}
})
//
"button 被 点击了"
这也是事件委托的优点:
- 省监听数(内存)
- 可以监听动态元素