0%

Event-delegate

什么是事件代理(也叫事件委托)

事件代理是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。比如,我们有一个ul元素,里面有很多li元素,我们想要给每个li元素添加点击事件。有两种方法可以完成这件事:

  1. 给每个li元素都添加一个点击事件,弊端是如果li元素很多的话,就会导致代码很冗余,如果后面还有新的li元素添加进来,还需要给新的li元素添加点击事件,导致代码很难维护。
  2. ul元素添加一个点击事件,然后在事件处理程序中判断点击的是哪个li元素,然后执行对应的操作即可,简洁高效。这种方法就是事件代理

事件代理的原理

事件代理的原理是利用事件冒泡,将本应由被点击元素处理了的事件委托给其父元素来处理,这样就可以在事件处理程序中判断点击的是哪个元素,然后执行对应的操作。
不支持事冒泡的事件无法使用事件代理,比如blurfocusloadunload等事件。

示例代码

下面代码为ul元素添加了一个点击事件,然后在事件处理程序中判断点击的是哪个li元素,然后执行对应的操作。

1
2
3
4
5
6
7
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
</ul>
1
2
3
4
5
6
const list = document.getElementById('list');
list.addEventListener('click', (e) => {
if (e.target && e.target.nodeName === 'LI') {
console.log(e.target.innerHTML);
}
});

而下面的代码为table元素添加了点击事件,然后在事件处理程序中判断点击的是哪个td元素,然后执行对应的操作。

1
2
3
4
5
6
7
8
9
10
<table id="my-table">
<tr>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
</tr>
</table>
1
2
3
4
5
6
7
8
9
const table = document.getElementById("my-table");
table.addEventListener("click", (e) => {
// Only handle click on td element.
if (e.target.tagName.toLowerCase() === "td") {
console.log(
`You clicked on td element with value ${e.target.innerHTML}`
);
}
});

为啥突然想到这个呢?

因为最近在做一个drag and drop的app,需要在拖拽的时候显示preview(被拖拽元素跟着鼠标走),需要一个操作就是克隆被拖拽的元素,而cloneNode这个方法是无法克隆事件的(只能克隆inline事件,无法克隆通过属性或者event listener添加的事件),而如果使用的是事件代理模式,则不存在这个问题。