源本科技 | 码上会

JavaScript 事件

2025/12/30
52
0

学习目标

  • 理解 JavaScript 事件的基本概念与触发机制

  • 掌握常见事件类型(鼠标、键盘、表单、窗口等)

  • 熟练使用三种事件绑定方式,优先采用 addEventListener

  • 深入理解事件冒泡捕获事件委托

  • 能够阻止默认行为(preventDefault)和停止传播(stopPropagation

  • 在实际项目中实现表单验证、动态内容、交互列表等典型应用


什么是 JavaScript 事件

事件(Event)是浏览器中发生的动作或状态变化,可以由用户操作(如点击、输入)或浏览器自身(如页面加载完成)触发。

<button onclick="myFun()">点击我</button>
<p id="main"></p>

<script>
function myFun() {
    document.getElementById("main").innerHTML = "Hello, Coder!";
}
</script>
  • 用户点击按钮 → 触发 click 事件

  • 执行 myFun() → 动态更新页面内容

事件让网页从“静态展示”变为“动态交互”。


常见事件类型

类别

事件示例

触发时机

鼠标事件

click, dblclick, mouseover, mouseout, mousemove

鼠标操作

键盘事件

keydown, keypress, keyup

键盘按键

表单事件

submit, change, focus, blur

表单交互

窗口事件

load, resize, scroll

页面或窗口状态变化

// 鼠标移动追踪
document.addEventListener("mousemove", (e) => {
    console.log(`鼠标位置: (${e.clientX}, ${e.clientY})`);
});

// 键盘按下监听
document.addEventListener("keydown", (e) => {
    console.log(`按下了键: ${e.key}`);
});

事件处理的三种方式

1. 内联 HTML 处理器

不推荐

<button onclick="alert('已点击!')">点击</button>

❌ 缺点:HTML 与 JS 耦合,难以维护,无法复用。


2. DOM 属性处理器

const btn = document.getElementById("myBtn");
btn.onclick = () => {
    alert("按钮被点击了!");
};

⚠️ 限制:只能绑定一个处理函数,后续赋值会覆盖前一个。


3. addEventListener()

推荐方式

btn.addEventListener("click", () => {
    alert("使用 addEventListener 触发!");
});

优势:

  • 可绑定多个监听器

  • 支持移除监听器removeEventListener

  • 可控制捕获 / 冒泡阶段

  • 更符合现代 Web 标准


事件传播:捕获与冒泡

事件在 DOM 树中传播分为两个阶段:

1. 捕获阶段

  • 从根节点(window)向下传递到目标元素

  • addEventListener 第三个参数设为 true 启用

2. 冒泡阶段(默认)

  • 从目标元素向上传播回根节点

// 捕获阶段监听
div.addEventListener("click", () => {
    console.log("Div(捕获阶段)");
}, true);

// 冒泡阶段监听(默认)
button.addEventListener("click", (e) => {
    console.log("Button(冒泡阶段)");
    e.stopPropagation(); // 阻止继续冒泡
});

默认情况下,所有事件监听器都在冒泡阶段执行。


事件委托

Event Delegation

原理:利用事件冒泡,将监听器绑定到父元素,统一处理子元素事件。

优势

  • 减少内存占用(只需一个监听器)

  • 动态添加的子元素自动生效

示例:交互式列表

<ul id="list">
    <li>项目 1</li>
    <li>项目 2</li>
    <li>项目 3</li>
</ul>

<script>
document.getElementById("list").addEventListener("click", (e) => {
    if (e.target.tagName === "LI") {
        e.target.style.backgroundColor = "yellow";
        console.log("点击了:", e.target.textContent);
    }
});
</script>

即使后续通过 JS 添加新的 <li>,点击依然有效!


阻止默认行为

某些元素有内置行为(如 <a> 跳转、<form> 提交),可用 preventDefault() 取消。

// 阻止链接跳转
document.querySelector("a").addEventListener("click", (e) => {
    e.preventDefault();
    console.log("链接跳转已被阻止");
});

// 表单验证示例
document.querySelector("#myForm").addEventListener("submit", (e) => {
    const input = document.querySelector("#username");
    if (!input.value.trim()) {
        e.preventDefault(); // 阻止提交
        alert("用户名不能为空!");
    }
});

preventDefault() 不影响事件传播,如需同时停止传播,需额外调用 stopPropagation()


实际应用场景

1. 表单验证

<form id="userForm">
    <input type="text" id="username" placeholder="请输入用户名" />
    <button type="submit">提交</button>
</form>

<script>
document.getElementById("userForm").addEventListener("submit", (e) => {
    const value = document.getElementById("username").value;
    if (!value) {
        e.preventDefault();
        alert("请输入内容!");
    }
});
</script>

2. 动态内容添加

document.getElementById("addBtn").addEventListener("click", () => {
    const newDiv = document.createElement("div");
    newDiv.textContent = "新元素已添加";
    newDiv.style.margin = "10px 0";
    newDiv.style.padding = "8px";
    newDiv.style.backgroundColor = "#f0f0f0";
    document.body.appendChild(newDiv);
});

3. 交互式列表

高亮点击项

document.getElementById("interactiveList").addEventListener("click", (e) => {
    if (e.target.matches("li")) {
        // 移除其他项的高亮
        document.querySelectorAll("#interactiveList li").forEach(li => {
            li.style.backgroundColor = "";
        });
        // 高亮当前项
        e.target.style.backgroundColor = "#ffeb3b";
    }
});

重点总结

概念

说明

事件类型

click, keydown, submit, load

绑定方式

优先使用 addEventListener

事件传播

捕获(自上而下)→ 目标 → 冒泡(自下而上)

事件委托

利用冒泡,在父元素统一处理子元素事件

阻止默认

e.preventDefault()

停止传播

e.stopPropagation()

最佳实践

解耦 HTML/JS、使用委托、避免内存泄漏


思考题

  1. 以下代码点击按钮后会输出什么?为什么?

    <div onclick="console.log('Div')">
        <button onclick="console.log('Button')">Click</button>
    </div>
  2. 如何实现一个“点击页面任意位置关闭弹窗”的功能?需要注意什么问题?(提示:考虑事件委托与阻止冒泡)