发布于 

为什么需要事件委托

什么是事件委托?事件委托的原理又是什么?事件冒泡和事件捕获的区别又在哪里?

要解答上面三个问题,我们要一步步弄清楚事件机制:事件流 -> 事件冒泡 -> 事件捕获 -> 事件委托

事件流描述了页面接收事件的顺序。IE 和 Netscape 开发团队提出了几乎完全相

反的事件流方案。IE 支持事件冒泡流,而 Netscape 支持事件捕获流。

事件冒泡

IE 事件流被称为事件冒泡,这是因为事件被定义为从最具体的元素(文档树中最深的节点)开始触

发,然后向上传播至没有那么具体的元素(文档)。比如有如下 HTML 页面:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html> 
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>

在点击页面中的

元素后,click 事件会以如下顺序发生:div -> body -> html -> document

也就是说,

元素,即被点击的元素,最先触发 click 事件。然后,click 事件沿 DOM 树一

路向上,在经过的每个节点上依次触发,直至到达 document 对象。

事件捕获

Netscape 团队提出了另一种名为事件捕获的事件流。事件捕获的意思是最不具体的节

点应该最先收到事件,而最具体的节点应该最后收到事件。事件捕获实际上是为了在事件到达最终目标

前拦截事件。如果前面的例子使用事件捕获,则点击

元素会以下列顺序触发 click 事件:document -> html -> body ->div

在事件捕获中,click 事件首先由 document 元素捕获,然后沿 DOM 树依次向下传播,直至到达

实际的目标元素

由于旧版本浏览器不支持,因此实际当中几乎不会使用事件捕获。通常建议使用事件冒泡,特殊情

况下可以使用事件捕获。

事件委托

“过多事件处理程序”的解决方案是使用事件委托。事件委托利用事件冒泡,可以只使用一个事件

处理程序来管理一种类型的事件。例如,click 事件冒泡到 document。这意味着可以为整个页面指定

一个 onclick 事件处理程序,而不用为每个可点击元素分别指定事件处理程序。

比如有以下HTML:

1
2
3
4
5
<ul id="myLinks"> 
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>

这里的 HTML 包含 3 个列表项,在被点击时应该执行某个操作。对此,通常的做法是像这样指定 3

个事件处理程序:

1
2
3
4
5
6
7
8
9
10
11
12
let item1 = document.getElementById("goSomewhere"); 
let item2 = document.getElementById("doSomething");
let item3 = document.getElementById("sayHi");
item1.addEventListener("click", (event) => {
location.href = "http:// www.wrox.com";
});
item2.addEventListener("click", (event) => {
document.title = "I changed the document's title";
});
item3.addEventListener("click", (event) => {
console.log
});

如果对页面中所有需要使用 onclick 事件处理程序的元素都如法炮制,结果就会出现大片雷同的

只为指定事件处理程序的代码。使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,

就可以解决问题。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let list = document.getElementById("myLinks"); 
list.addEventListener("click", (event) => {
let target = event.target;
switch(target.id) {
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.href = "http:// www.wrox.com";
break;
case "sayHi":
console.log("hi");
break;
}
});

这里只给