JavaScript addEventListener:更灵活的事件绑定方式
在网页开发中,让页面响应用户操作,核心就是事件处理。之前我们聊过可以直接在 HTML 标签里用 onclick 这样的属性来绑定事件。但这种方式有个局限:一个元素的一个事件类型,只能绑定一个处理函数。如果我想让一个按钮被点击时,同时做三件事——比如弹提示、改文字、发请求——用 onclick 就不太方便了。
addEventListener 就是来解决这个问题的。它是在 DOM API 层面提供的方法,让我们可以给同一个元素的同一个事件,绑定多个处理函数,彼此互不干扰。这也是我后来写项目时更倾向用的方式。
addEventListener 的基本语法
element.addEventListener(event, function, useCapture);
参数说明:
-
element:要监听事件的 DOM 元素,比如document、button、div,甚至window对象。 -
event:事件名称,字符串形式。注意不要带on前缀,比如用"click"而不是"onclick"。 -
function:事件触发时要执行的函数,可以是命名函数,也可以是匿名函数。 -
useCapture(可选):布尔值,指定事件是在捕获阶段还是冒泡阶段执行。默认false,表示冒泡阶段。
为什么选择 addEventListener?
用 addEventListener 有几个明显的好处:
-
可以绑定多个处理函数:同一个事件可以绑定多个函数,它们会按添加顺序依次执行。
-
更精细的控制:可以通过第三个参数控制事件传播阶段(捕获或冒泡)。
-
便于移除:配合
removeEventListener,可以精确移除某个事件处理函数。 -
代码分离:把 JavaScript 从 HTML 中分离出来,维护起来更清晰。
基础示例:给按钮绑定点击事件
先来看一个最基础的用法。在“代码号”学习环境里,我们创建一个按钮,点击后在页面上显示一段文字。
<!DOCTYPE html>
<html>
<body>
<h3>addEventListener 基础示例</h3>
<button id="demoBtn">点我试试</button>
<p id="message"></p>
<script>
// 获取按钮元素
let btn = document.getElementById("demoBtn");
// 定义事件处理函数
function showMessage() {
document.getElementById("message").innerHTML = "2026年3月23日 按钮被点击了";
}
// 绑定事件
btn.addEventListener("click", showMessage);
</script>
</body>
</html>
说明:这里我们用 getElementById 拿到按钮,然后用 addEventListener 把 click 事件和 showMessage 函数关联起来。用户点击时,函数就会执行。
示例:给同一个元素绑定多个点击事件
这是 addEventListener 的优势所在。同一个按钮的点击事件,我们可以绑多个处理函数。
<!DOCTYPE html>
<html>
<body>
<h3>多个事件处理函数示例</h3>
<button id="multiBtn">点击我</button>
<p id="output1"></p>
<p id="output2"></p>
<script>
let btn = document.getElementById("multiBtn");
// 第一个处理函数:弹出提示
function firstAction() {
alert("这是第一个处理函数");
}
// 第二个处理函数:修改第一个段落
function secondAction() {
document.getElementById("output1").innerHTML = "第一个处理函数执行后的结果";
}
// 第三个处理函数:修改第二个段落
function thirdAction() {
document.getElementById("output2").innerHTML = "第二个处理函数执行后的结果";
}
// 给同一个 click 事件绑定三个函数
btn.addEventListener("click", firstAction);
btn.addEventListener("click", secondAction);
btn.addEventListener("click", thirdAction);
</script>
</body>
</html>
说明:点击按钮后,三个函数会按添加顺序依次执行。先弹提示框,然后两个段落依次更新。如果用的是 onclick 属性,后面的会覆盖前面的,做不到这种效果。
示例:给同一个元素绑定不同类型的事件
除了相同类型的事件可以绑多个,不同类型的事件也可以绑在同一个元素上。比如鼠标移入、鼠标移出、点击,可以分别做不同的事。
<!DOCTYPE html>
<html>
<body>
<h3>不同类型事件示例</h3>
<button id="styleBtn" style="padding: 10px 20px;">鼠标移过来试试</button>
<p id="status"></p>
<script>
let btn = document.getElementById("styleBtn");
let statusP = document.getElementById("status");
// 鼠标移入:改变按钮样式
btn.addEventListener("mouseover", function() {
btn.style.backgroundColor = "#ff6b6b";
btn.style.color = "white";
statusP.innerHTML = "鼠标移入,按钮变色了";
});
// 鼠标移出:恢复样式
btn.addEventListener("mouseout", function() {
btn.style.backgroundColor = "";
btn.style.color = "";
statusP.innerHTML = "鼠标移出,样式恢复";
});
// 点击事件:显示点击信息
btn.addEventListener("click", function() {
statusP.innerHTML = "按钮被点击了,时间是 2026年3月23日";
});
</script>
</body>
</html>
说明:鼠标移入时触发样式变化,移出时恢复,点击时显示文字。三种事件互不干扰,各自处理各自的逻辑。
示例:给 window 对象添加事件监听
addEventListener 不仅能用在普通 DOM 元素上,还能用在 window 对象上,监听全局事件。比如监听窗口尺寸变化、页面滚动、键盘按键等。
<!DOCTYPE html>
<html>
<head>
<style>
body {
height: 2000px;
transition: background-color 0.2s;
margin: 0;
padding: 20px;
}
.info {
position: fixed;
top: 10px;
right: 10px;
background: rgba(0,0,0,0.7);
color: white;
padding: 10px;
border-radius: 5px;
font-size: 14px;
}
</style>
</head>
<body>
<h3>监听 window 对象事件</h3>
<p>试试调整窗口大小、滚动页面、或者按键盘上的键</p>
<div class="info" id="windowInfo">等待操作...</div>
<script>
let infoDiv = document.getElementById("windowInfo");
// 监听窗口尺寸变化
window.addEventListener("resize", function() {
let width = window.innerWidth;
let height = window.innerHeight;
infoDiv.innerHTML = `窗口尺寸: ${width} x ${height}`;
});
// 监听页面滚动
window.addEventListener("scroll", function() {
let scrollPos = window.scrollY;
// 根据滚动位置改变背景色,做一个简单的视觉效果
let r = scrollPos % 255;
let g = 150;
let b = 255 - (scrollPos % 100);
document.body.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
infoDiv.innerHTML = `滚动位置: ${scrollPos}px`;
});
// 监听键盘按键
window.addEventListener("keydown", function(event) {
infoDiv.innerHTML = `按下了按键: ${event.key}`;
// 按 ESC 键时清空信息
if (event.key === "Escape") {
infoDiv.innerHTML = "按下了 ESC 键,已清空";
}
});
</script>
</body>
</html>
说明:这里我们监听了三个窗口级别的事件。resize 在窗口大小改变时触发,scroll 在页面滚动时触发,keydown 在键盘按下时触发。这种全局监听在开发一些交互工具时很实用。
事件传播:捕获与冒泡
addEventListener 的第三个参数 useCapture 控制事件是在捕获阶段还是冒泡阶段执行。理解这个概念,对处理嵌套元素的事件很有帮助。
简单说,当一个元素内部还有子元素,且父子元素都绑定了同一个事件时:
-
冒泡(默认,
useCapture = false):事件从最内层元素开始,向外层元素依次触发。 -
捕获(
useCapture = true):事件从最外层元素开始,向内层元素依次触发。
<!DOCTYPE html>
<html>
<head>
<style>
.outer {
background-color: #4a90e2;
padding: 40px;
margin: 20px;
cursor: pointer;
}
.inner {
background-color: #f39c12;
padding: 40px;
text-align: center;
color: white;
cursor: pointer;
}
</style>
</head>
<body>
<h3>事件传播:捕获 vs 冒泡</h3>
<div class="outer" id="outerDiv">
外层元素
<div class="inner" id="innerDiv">内层元素(点击这里)</div>
</div>
<p id="log"></p>
<script>
let outer = document.getElementById("outerDiv");
let inner = document.getElementById("innerDiv");
let log = document.getElementById("log");
// 外层使用捕获模式 (true)
outer.addEventListener("click", function() {
log.innerHTML += "外层元素被触发(捕获阶段)<br>";
}, true);
// 内层使用冒泡模式 (false)
inner.addEventListener("click", function() {
log.innerHTML += "内层元素被触发(冒泡阶段)<br>";
}, false);
// 外层也加一个冒泡模式的监听,看看顺序
outer.addEventListener("click", function() {
log.innerHTML += "外层元素被触发(冒泡阶段)<br>";
}, false);
</script>
</body>
</html>
说明:点击内层元素时,执行顺序是:外层捕获阶段 → 内层冒泡阶段 → 外层冒泡阶段。如果只关心顺序,默认用冒泡模式(false)就够用了,捕获模式通常在需要“先拦截”事件的场景下使用。
移除事件监听:removeEventListener
绑定的事件如果不再需要,应该及时移除,避免内存泄漏。移除时需要注意:传入的函数必须是同一个引用,不能用匿名函数。
<!DOCTYPE html>
<html>
<body>
<h3>移除事件监听示例</h3>
<button id="actionBtn">点我有效</button>
<button id="removeBtn">移除监听</button>
<p id="clickStatus"></p>
<script>
let actionBtn = document.getElementById("actionBtn");
let removeBtn = document.getElementById("removeBtn");
let statusP = document.getElementById("clickStatus");
// 定义一个命名函数
function handleClick() {
statusP.innerHTML = "按钮被点击了,时间是 2026年3月23日";
}
// 绑定事件
actionBtn.addEventListener("click", handleClick);
// 移除事件
removeBtn.addEventListener("click", function() {
actionBtn.removeEventListener("click", handleClick);
statusP.innerHTML = "事件监听已被移除,按钮不再响应点击";
});
</script>
</body>
</html>
说明:第一个按钮的点击事件绑定了 handleClick 函数。点击第二个按钮时,通过 removeEventListener 把同一个函数移除掉。之后再点第一个按钮,就不会有反应了。
本节课程知识要点
-
多事件绑定:
addEventListener允许为同一元素的同一事件绑定多个处理函数,按添加顺序执行,这是它相较于onclick属性的核心优势。 -
事件类型不带
on前缀:使用时注意事件名是字符串,如"click"、"mouseover",而不是"onclick"。 -
事件传播阶段:第三个参数
useCapture控制事件在捕获阶段还是冒泡阶段执行。默认false(冒泡),大多数场景下保持默认即可。 -
window对象事件:可以监听全局事件,如resize、scroll、keydown,适合做页面级别的交互。 -
移除监听的条件:
removeEventListener需要传入与添加时相同的函数引用。绑定事件时尽量使用命名函数,而不是匿名函数,这样后续才能精确移除。 -
性能考量:在单页应用或动态增删元素的场景中,及时移除不再需要的事件监听,有助于避免内存泄漏,保持页面流畅。