一、事件流
1)DOM事件流
DOM2 Events 规范规定事件流分为 3 个阶段
:事件捕获、到达目标和事件冒泡
。事件捕获最先发生,为提前拦截事件提供了可能。然后,实际的目标元素接收到事件。最后一个阶段是冒泡,最迟要在这个阶段响应事件。
1.捕获阶段
- 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
2.目标阶段
- 事件捕获到目标元素,捕获结束开始在目标元素上触发事件
3.冒泡阶段
- 事件从目标元素向他的祖先元素传递
,依次触发祖先元素上的事件
- 如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true
一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
2) 事件冒泡(Bubble)
- 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
- 在冒泡中,最内侧元素的事件会首先被处理,然后是更外侧的:首先处理 <p> 元素的点击事件,然后是 <div>元素的点击事件。
- 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1{
width: 200px;
height: 200px;
background-color: yellowgreen;
}
#s1{
background-color: yellow;
}
</style>
</head>
<body>
<div id="box1">
我是box1
<span id="s1">我是span</span>
</div>
<script type="text/javascript">
//为s1绑定一个单击响应函数
var s1 = document.getElementById("s1");
s1.onclick = function(event){
event = event || window.event;
alert("我是span的单击响应函数");
//取消冒泡
//可以将事件对象的cancelBubble设置为true,即可取消冒泡,或者设置event.stopPropagation()
//event.cancelBubble = true;
//event.stopPropagation()
};
//为box1绑定一个单击响应函数
var box1 = document.getElementById("box1");
box1.onclick = function(event){
event = event || window.event;
alert("我是div的单击响应函数");
//event.cancelBubble = true;
};
//为body绑定一个单击响应函数
document.body.onclick = function(){
alert("我是body的单击响应函数");
};
</script>
</body>
</html>
运行结果:
点击span前:
点击span后:(引发各个祖先事件响应)
3) 事件捕获
- 在捕获中,最外侧元素的事件会首先被处理,然后是更内侧的:首先处理外部元素的点击事件,然后是内部元素的点击事件。
二、事件委托(事件代理)
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。将本应该绑定给子元素的事件代理给父元素
。
目的: 减少dom操作浏览器的重排和重绘,并且新添加的元素也是有事件的。
案例:
<script>
window.onload = function() {
// 要求给所有的li标签绑定事件 点击每一个li标签背景色变成红色
var ul = document.getElementsByTagName('ul')[0];
// var lis=document.getElementsByTagName('li');
// for(let i=0;i<lis.length;i++){
// lis[i].οnclick=function(){
// this.style.backgroundColor='red'
// }
// }
// 利用事件委托 利用事件冒泡(方法一)
//ul.onclick = function(e) {
// e.target.style.backgroundColor = 'red';
//}
//var newLi = document.createElement('li');
//newLi.innerHTML = '我是一个新的li';
//ul.appendChild(newLi);
// 事件委托 (方法二)
ul.addEventListener('click', function(e) {
if (e.target.localName === "li") {
e.target.style.backgroundColor = 'red';
}
})
}
</script>
</head>
<body>
<ul>
<li>1个li标签</li>
<li>2个li标签</li>
<li>3个li标签</li>
<li>4个li标签</li>
<li>5个li标签</li>
<li>6个li标签</li>
<li>7个li标签</li>
<li>8个li标签</li>
<li>9个li标签</li>
<li>10个li标签</li>
</ul>
</body>
运行结果:
事件委托的优点:
-
document 对象随时可用,
任何时候都可以给它添加事件处理程序
(不用等待 DOMContentLoaded或 load 事件)。这意味着只要页面渲染出可点击的元素,就可以无延迟地起作用。 -
节省花在设置页面事件处理程序上的时间
。只指定一个事件处理程序既可以节省 DOM 引用,也可以节省时间。 -
减少整个页面所需的内存,提升整体性能