1、事件冒泡
当触发子元素的事件时,该子元素的所有“父级元素” 的“同名事件”会依次触发
- 事件冒泡现象一直都存在,只是以前没有给父元素注册同名事件
- 子元素 → 父元素 → body → html → document → window
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: pink;
}
.son {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let father = document.querySelector('.father')
let son = document.querySelector('.son')
//子元素
son.onclick = function () {
alert('我是son')
}
//父元素
father.onclick = function () {
alert('我是father')
}
//body
document.body.onclick = function () {
alert('我是body')
}
//html
document.documentElement.onclick = function () {
alert('我是html')
}
//document
document.onclick = function () {
alert('我是document')
}
//window
window.onclick = function () {
alert('我是window')
}
</script>
</body>
</html>
2、事件委托
给父元素注册事件,委托子元素来处理
- 事件委托原理:
事件冒泡 - 事件委托注意点 : 不能使用
this this: 事件源,指向父元素e.target: 事件触发源,指向具体触发这个事件委托的子元素
需求:给每一个li元素注册点击事件,点击之后显示自己的文本
方式一:以前的方法,遍历数组逐一注册
<body>
<ul>
<li>扬帆起航1</li>
<li>扬帆起航2</li>
<li>扬帆起航3</li>
<li>扬帆起航4</li>
<li>扬帆起航5</li>
<li>扬帆起航6</li>
</ul>
<script>
let liList = document.querySelectorAll('ul>li');
for (let i = 0; i < liList.length; i++) {
liList[i].onclick = function () {
alert(this.innerText)
}
}
</script>
</body>
方式二:使用事件冒泡,给父元素注册
<body>
<ul>
<li>扬帆起航1</li>
<li>扬帆起航2</li>
<li>扬帆起航3</li>
<li>扬帆起航4</li>
<li>扬帆起航5</li>
<li>扬帆起航6</li>
</ul>
<script>
let ul = document.querySelector('ul')
ul.onclick = function (e) {
alert(e.target.innerText)
}
</script>
</body>
3、事件捕获
事件捕获,与事件冒泡完全相反
- 会先从最顶级父元素
window一级一级往下触发 - window -> document -> html -> body -> 父元素 -> 子元素
- 默认情况下注册的事件都是冒泡类型事件
- 只有唯一的一种语法可以注册捕获类型事件:
事件源.addEventListener('事件类型',事件处理函数,true): 第三个参数为true
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: pink;
}
.son {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let father = document.querySelector('.father')
let son = document.querySelector('.son')
//◆子元素
son.addEventListener(
'click',
function () {
alert('我是son')
},
true
) //捕获
//◆父元素
father.addEventListener(
'click',
function () {
alert('我是father')
},
true
)
//◆body
document.body.addEventListener(
'click',
function (e) {
alert('我是body')
},
true
)
//◆html
document.documentElement.addEventListener(
'click',
function () {
alert('我是html')
},
true
)
//◆document
document.addEventListener(
'click',
function () {
alert('我是document')
},
true
)
//◆window
window.addEventListener(
'click',
function () {
alert('我是window')
},
true
)
</script>
</body>
</html>
4、事件流三个阶段 : e.eventPhase获取事件阶段
捕获阶段>目标阶段>冒泡阶段
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: pink;
}
.son {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let father = document.querySelector('.father')
let son = document.querySelector('.son')
//◆子元素
son.addEventListener(
'click',
function (e) {
alert('我是son :' + e.eventPhase)
},
false
) //冒泡
//◆父元素
father.addEventListener(
'click',
function (e) {
alert('我是father:' + e.eventPhase)
e.stopPropagation()
},
false
)//冒泡
//◆body
document.body.addEventListener(
'click',
function (e) {
alert('我是body:' + e.eventPhase)
},
false
)//冒泡
//◆html
document.documentElement.addEventListener(
'click',
function (e) {
alert('我是html:' + e.eventPhase)
},
false
) //冒泡
//◆document
document.addEventListener(
'click',
function (e) {
alert('我是document:' + e.eventPhase)
},
true
) //捕获
//◆window
window.addEventListener(
'click',
function (e) {
alert('我是window :' + e.eventPhase)
},
true
) //捕获
</script>
</body>
</html>
- 如果点击子元素:window(1)>document(1)>子元素(2)>父元素(3)
- 如果点击父元素:window(1)>document(1)>父元素(2)
- 如果点击body:window(1)>document(1)>html(2)
IE 浏览器只支持冒泡不支持捕获,W3C 浏览器先执行捕获,后执行冒泡
5、阻止事件流动: e.stopPropagation()
无论是冒泡还是捕获都可以阻止(停止事件流),但不会阻止默认行为(a标签、form表单)
W3C 的方法是
e.stopPropagation(),IE则是使用e.cancelBuble=true
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: pink;
}
.son {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
let father = document.querySelector('.father')
let son = document.querySelector('.son')
//◆子元素
son.onclick = function (e) {
e.stopPropagation()
alert('我是son')
}
//◆父元素
father.onclick = function (e) {
e.stopPropagation()
alert('我是father')
}
//◆body
document.body.onclick = function (e) {
e.stopPropagation()
alert('我是body')
}
//◆html
document.documentElement.onclick = function (e) {
e.stopPropagation()
alert('我是html')
}
//◆document
document.onclick = function (e) {
e.stopPropagation()
alert('我是document')
}
//◆window
window.onclick = function (e) {
e.stopPropagation()
alert('我是window')
}
</script>
</body>
</html>
点击子元素不会冒泡,点击父元素也不会冒泡......
6、阻止默认行为,e.preventDefault()
W3C 的方法是
e.preventDefault(),IE则是使用e.returnValue=false
<body>
<a id="txt" href="http://www.baidu.com">不想去百度</a>
</body>
<script>
let a = document.getElementById('txt')
a.onclick = function (e) {
if (e.preventDefault) {
e.preventDefault()
} else {
window.event.returnValue = false
}
}
</script>
以上代码优化
<body>
<a id="txt" href="http://www.baidu.com">不想去百度</a>
</body>
<script>
let a = document.getElementById('txt')
a.onclick = function (e) {
window.event ? window.event.returnValue = false : e.preventDefault()
}
</script>