JavaScript事件机制

本文最后更新于 2025年7月30日 下午

参考:
https://juejin.cn/post/6844903445418213383
https://juejin.cn/post/6844904097372438542

在 JavaScript 的学习中,经常会遇到 JavaScript 的事件机制,例如,事件绑定、事件监听、事件委托等。

事件绑定

要想让 JavaScript 对用户的操作作出响应,首先要对 DOM 元素绑定事件处理函数。所谓事件处理函数,就是处理用户操作的函数,不同的操作对应不同的名称。

在 JavaScript 中,有三种常用的绑定事件的方法:

  • 在 DOM 元素中直接绑定事件
  • 在 JavaScript 代码中绑定事件
  • 使用事件监听绑定事件

在 DOM 元素中直接绑定事件

在 DOM 元素上绑定 onclick、onmouseover、onmouseout、onmousedown、onmouseup、ondblclick、onkeydown、onkeypress、onkeyup 等事件。

在 JavaScript 代码中绑定事件

在 JavaScript 代码中(即 script 标签内)绑定事件可以使 JavaScript 代码与 HTML 标签分离,文档结构清晰,便于管理和开发。

使用事件监听绑定事件

另一种方法是用 addEventListener() 或 attachEvent() 来绑定事件监听函数。

事件监听

对于事件监听,W3C 规范中定义了 3 个事件阶段,依次是捕获阶段、目标阶段、冒泡阶段。

  • 事件冒泡:事件开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点或文档。
  • 事件捕获:事件开始由不太具体的节点接收,然后逐级向下传播到最具体的节点。与事件冒泡相反。

W3C 语法:

1
element.addEventListener(event, function, useCapture)
  • event(必需):事件名,支持所有 DOM 事件
  • function(必需):指定事件触发时要执行的函数
  • useCapture(可选):指定事件是在捕获还是冒泡阶段执行。false 冒泡阶段(默认),true 捕获阶段

事件监听优点

  • 可以绑定多个事件
  • 可以解除相应的绑定

封装事件监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 绑定监听事件
function addEventHandler(target, type, fn) {
if (target.addEventListener) {
target.addEventListener(type, fn);
} else {
target.attachEvent("on" + type, fn);
}
}
// 移除监听事件
function removeEventHandler(target, type, fn) {
if (target.removeEventListener) {
target.removeEventListener(type, fn);
} else {
target.detachEvent("on" + type, fn);
}
}
//测试
const btn5 = document.getElementById("btn5");
addEventHandler(btn5, "click", hello1); // 添加事件hello1
addEventHandler(btn5, "click", hello2); // 添加事件hello2
removeEventHandler(btn5, "click", hello1); // 移除事件hello1

事件委托

事件委托就是利用冒泡的原理,将元素的事件委托给它的父元素或祖先元素上,触发执行效果。

1
2
3
4
5
<ul id="myLink">
<li id="1">aaa</li>
<li id="2">bbb</li>
<li id="3">ccc</li>
</ul>

不使用事件委托

1
2
3
4
5
6
7
8
9
10
const myLink = document.getElementById("myLink");
const li = myLink.getElementsByTagName("li");

for (let i = 0; i < li.length; i++) {
li[i].onclick = function (e) {
let e = event || window.event;
let target = e.target || e.srcElement;
alert(e.target.id + ":" + e.target.innerText);
};
}

缺点:

  • 给每一个列表都绑定事件,消耗内存
  • 当有动态添加的元素时,需要重新给元素绑定事件

使用事件委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function delegate(element, eventType, selector, fn) {
element.addEventListener(eventType, (e) => {
let el = e.target;
while (!el.matches(selector)) {
if (element === el) {
el = null;
break;
}
el = el.parentNode;
}
el && fn.call(el, e, el);
});
return element;
}

优点:

  • 提高 JavaScript 性能。事件委托可以显著的提高事件的处理速度,减少内存的占用
  • 动态添加 DOM 元素。不需要因元素的改动而修改事件绑定

注意:

  • 事件委托的实现依靠的冒泡,因此不支持事件冒泡的事件不适合使用事件委托
  • 不是所有的事件绑定都适合用事件委托,不恰当使用反而可能导致不需要绑定事件的元素也被绑定事件

JavaScript事件机制
https://xuekeven.github.io/2021/09/13/JavaScript事件机制/
作者
Keven
发布于
2021年9月13日
更新于
2025年7月30日
许可协议