关于事件代理

上次面试的时候没有回答出来!
可恶!
只记得刚入坑前端的时候又看到过,就再也没有接触了,来填一填坑。

参考链接

js 中的事件委托或事件代理详解
JavaScript 事件代理和委托
事件的代理

《JavaScript 高级程序设计》
P346 13.1.1 事件冒泡
P402 13.5.1 事件委托

事件流

解决的问题:
页面的哪一部分会拥有特定的事件?

简单来说就是单击了某个按钮,并不仅仅是发生在按钮上,还发生在按钮的容元素,甚至单击了整个页面。

事件流描述的是从页面中接收事件的顺序。

IE 的事件流是事件冒泡流,而 Netscape Communicator 的事件流是事件捕获流

事件冒泡

IE 的事件流叫做事件冒泡 (event bubbling),即事件开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

1
2
3
4
5
6
7
8
9
<! DOCYTPE html>
<html>
<head>
<title>event bubbling demo</title>
</head>
<body>
<div>click here</div>
</body>
</html>

在上面的例子中,点击了 div 之后,click 事件会从 div -> body -> html -> document 这样传播。

事件捕获

Netscape Communicator 团队提出的事件流。

区别在于上面的例子里,click 事件会从 document -> html -> body -> div 这样传播。

IE9 以及其他主流浏览器也都支持事件捕获但是由于老版本浏览器兼容性问题,建议放心的使用事件冒泡。

事件代理

也称为事件委托

解决的问题是"事件处理程序过多"。

目的就是性能优化啦。

  1. 每一个函数(事件处理程序就是函数)都是一个对象,是对象就会占用内存。
  2. 众所周知 DOM 操作越多,性能越不好。

事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<body>
<ul id="ul">
<li id="li_1">1</li>
<li id="li_2">2</li>
<li id="li_3">3</li>
<li id="li_4">4</li>
</ul>
<script>
let ul = document.getElementById("ul");
ul.addEventListener("click", e => {
const target = e.target;
if (target.nodeName.toLocaleLowerCase() === "li") {
switch (target.id) {
case "li_1":
console.log(target.id);
break;
case "li_2":
console.log(target.id);
break;
case "li_2":
console.log(target.id);
break;
default:
console.log(target.id);
break;
}
}
});
</script>
</body>

原理:

  1. event 对象的 target 属性为事件的目标节点。
  2. 所有的 li 都是 ul 元素的子节点,并且会冒泡,所以点击事件会被这个函数处理。
  3. 只获取了一个 DOM 元素,只添加了一个事件处理程序,所以占用的内存更少。

总结

最适合采用事件委托技术的事件包括click、mousedown、keydown、keyup和keypress。虽然mouseover和mouseout事件也冒泡,但是要适应他们并不容易,而且经常需要计算元素的位置。(因为当鼠标从一个元素移到其子节点时,或者鼠标移除该元素时,都会触发mouseout事件。) – –《JavaScript高级程序设计》

以及还有就是需要为新建的元素添加事件监听也可以采用事件委托来实现自动添加监听事件。

0%