← JavaScript 事件处理 没有下一篇了 →

JavaScript addEventListener

原创 2026-03-23 JavaScript 已有人查阅

JavaScript addEventListener:更灵活的事件绑定方式

在网页开发中,让页面响应用户操作,核心就是事件处理。之前我们聊过可以直接在 HTML 标签里用 onclick 这样的属性来绑定事件。但这种方式有个局限:一个元素的一个事件类型,只能绑定一个处理函数。如果我想让一个按钮被点击时,同时做三件事——比如弹提示、改文字、发请求——用 onclick 就不太方便了。

addEventListener 就是来解决这个问题的。它是在 DOM API 层面提供的方法,让我们可以给同一个元素的同一个事件,绑定多个处理函数,彼此互不干扰。这也是我后来写项目时更倾向用的方式。

addEventListener 的基本语法

element.addEventListener(event, function, useCapture);

参数说明:

  • element:要监听事件的 DOM 元素,比如 documentbuttondiv,甚至 window 对象。

  • event:事件名称,字符串形式。注意不要带 on 前缀,比如用 "click" 而不是 "onclick"

  • function:事件触发时要执行的函数,可以是命名函数,也可以是匿名函数。

  • useCapture(可选):布尔值,指定事件是在捕获阶段还是冒泡阶段执行。默认 false,表示冒泡阶段。

为什么选择 addEventListener?

用 addEventListener 有几个明显的好处:

  1. 可以绑定多个处理函数:同一个事件可以绑定多个函数,它们会按添加顺序依次执行。

  2. 更精细的控制:可以通过第三个参数控制事件传播阶段(捕获或冒泡)。

  3. 便于移除:配合 removeEventListener,可以精确移除某个事件处理函数。

  4. 代码分离:把 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 把同一个函数移除掉。之后再点第一个按钮,就不会有反应了。

本节课程知识要点

  1. 多事件绑定addEventListener 允许为同一元素的同一事件绑定多个处理函数,按添加顺序执行,这是它相较于 onclick 属性的核心优势。

  2. 事件类型不带 on 前缀:使用时注意事件名是字符串,如 "click""mouseover",而不是 "onclick"

  3. 事件传播阶段:第三个参数 useCapture 控制事件在捕获阶段还是冒泡阶段执行。默认 false(冒泡),大多数场景下保持默认即可。

  4. window 对象事件:可以监听全局事件,如 resizescrollkeydown,适合做页面级别的交互。

  5. 移除监听的条件removeEventListener 需要传入与添加时相同的函数引用。绑定事件时尽量使用命名函数,而不是匿名函数,这样后续才能精确移除。

  6. 性能考量:在单页应用或动态增删元素的场景中,及时移除不再需要的事件监听,有助于避免内存泄漏,保持页面流畅。

← JavaScript 事件处理 没有下一篇了 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号