JavaScript: JavaScript 事件

事件是用户或浏览器发出的"信号"——用户点了按钮、按了键盘、提交了表单,浏览器加载完页面……这些都是事件。你的代码"监听"这些事件,就能在恰当的时机做出响应。这就像门铃响了你去开门——门铃是事件,开门是响应。


1. 事件绑定方式

JavaScript 有三种给元素绑定事件处理函数的方式:

▶ 示例

JAVASCRIPT
// 本节代码示例
const message = "你好,世界!";
console.log(message);
▶ 试一试

这是最简单的示例,后续章节会详细解释。### (1) 1. HTML 属性(不推荐)

HTML
<button onclick="alert('别用这种方式')">点我</button>

HTML 和 JS 混在一起,难以维护,不推荐。

(2) 2. DOM 属性

HTML
<button id="myBtn">点我</button>
<script>
const btn = document.getElementById('myBtn');
btn.onclick = function() {
  console.log('点击了');
};
</script>

HTML 和 JS 分离了,但一个事件只能绑一个处理函数——后赋值会覆盖前赋值。

(3) 3. addEventListener(推荐)

HTML
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<script>
const btn1 = document.getElementById('btn1');
const btn2 = document.getElementById('btn2');
btn1.addEventListener('click', function() {
  console.log('处理函数1');
});
btn1.addEventListener('click', function() {
  console.log('处理函数2');
});
</script>

同一个事件可以绑多个处理函数,还能用 removeEventListener 移除,是最灵活的方式。

💡 提示: 三种方式的取舍:忘掉前两种,始终用 addEventListener。它不会覆盖已有监听器,还能控制冒泡/捕获阶段,是现代开发的唯一选择。



2. addEventListener 与 removeEventListener

HTML
<script>
element.addEventListener('事件名', 处理函数, 选项);
element.removeEventListener('事件名', 处理函数);
</script>
⚠️ 注意: removeEventListener 的处理函数必须和 addEventListener 传入的是同一个引用。匿名函数无法移除!需要移除时,必须把函数单独定义。

HTML
<button id="btn">测试</button>
<script>
const btn = document.getElementById('btn');

function handler() { console.log('只触发一次'); }
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);  // 成功移除

btn.addEventListener('click', function() { console.log('匿名'); });
btn.removeEventListener('click', function() { console.log('匿名'); });  // 移除失败!
</script>


3. 常见事件类型

类别 事件 说明
鼠标 clickdblclick 单击、双击
鼠标 mouseovermouseout 鼠标移入/移出
键盘 keydownkeyup 按键按下/松开
表单 submit 表单提交
表单 change 值改变并失焦后触发
表单 input 值实时改变(每输一个字符)
页面 load 页面及资源全部加载完
页面 DOMContentLoaded HTML 解析完即触发(不等图片)
💡 提示: change vs inputinput 是打字就触发,change 是输入完失焦才触发。实时搜索用 input,表单验证用 change



4. 事件对象 event

事件处理函数会收到一个事件对象参数,通常叫 event 或简写 e

属性/方法 说明
e.target 触发事件的元素(真正被点击的那个)
e.type 事件类型,如 'click'
e.preventDefault() 阻止默认行为(如阻止链接跳转、表单提交)
e.stopPropagation() 阻止事件冒泡

▶ 示例:按钮点击计数

HTML
<button id="counter">点击了 0 次</button>

<script>
const btn = document.getElementById('counter');
let count = 0;

btn.addEventListener('click', function(e) {
  count++;
  btn.textContent = '点击了 ' + count + ' 次';
  console.log('事件类型:', e.type);
  console.log('触发元素:', e.target.tagName);
});
</script>
▶ 试一试

▶ 示例:键盘检测

HTML
<p>按下任意键查看信息</p>
<div id="info" style="padding: 10px; border: 1px solid #ccc; min-height: 30px;"></div>

<script>
const info = document.getElementById('info');

document.addEventListener('keydown', function(e) {
  info.innerHTML = '按键: <b>' + e.key + '</b> | 键码: ' + e.keyCode + ' | Ctrl: ' + e.ctrlKey + ' | Shift: ' + e.shiftKey;
});
</script>
▶ 试一试

▶ 示例:表单拦截

HTML
<form id="myForm">
  <input type="text" id="name" placeholder="输入姓名" required>
  <button type="submit">提交</button>
</form>
<p id="result"></p>

<script>
const form = document.getElementById('myForm');
const result = document.getElementById('result');

form.addEventListener('submit', function(e) {
  e.preventDefault();
  const name = document.getElementById('name').value;
  result.textContent = '你好, ' + name + '! 表单已被拦截,没有真正提交。';
});
</script>
▶ 试一试

▶ 示例:事件委托

HTML
<ul id="menu">
  <li>首页</li>
  <li>关于</li>
  <li>联系</li>
  <li>帮助</li>
</ul>
<p id="selected"></p>

<script>
const menu = document.getElementById('menu');
const selected = document.getElementById('selected');

menu.addEventListener('click', function(e) {
  if (e.target.tagName === 'LI') {
    selected.textContent = '你选择了: ' + e.target.textContent;
  }
});
</script>
▶ 试一试
💡 提示: 上面这个技巧叫"事件委托"——把监听器绑在父元素上,用 e.target 判断真正被点击的子元素。不用给每个 li 单独绑事件,新增子元素也自动生效。这就是冒泡机制的妙用。



5. 事件冒泡与捕获

DOM 事件传播分三个阶段:

  1. 捕获阶段:事件从 window 一路向下传到目标元素
  2. 目标阶段:事件到达实际触发的元素
  3. 冒泡阶段:事件从目标元素一路向上冒泡回 window

默认情况下,addEventListener 在冒泡阶段触发。设第三个参数为 true 则在捕获阶段触发。

HTML
     window
       ↓ 捕获
    document
       ↓
      body
       ↓
   目标元素 ← 目标阶段
       ↑ 冒泡
      body
       ↑
    document
       ↑
     window
💡 提示: 大多数情况下你不需要关心捕获,用默认的冒泡就够了。e.stopPropagation() 可以阻止事件继续传播,但别滥用——它可能打断事件委托。


❓ 常见问题

Q e.targete.currentTarget 有什么区别?
A e.target 是真正触发事件的元素(你点的那一个),e.currentTarget 是当前正在执行处理函数的元素(绑监听器的那个)。在事件委托中两者不同,在直接绑定时两者相同。
Q 为什么表单提交后页面刷新了?
A <form>submit 事件默认行为就是提交并刷新页面。调用 e.preventDefault() 可以阻止它,然后用 JS 处理数据。
Q onclickaddEventListener('click') 能同时用吗?
A 能,但 onclick 赋值会覆盖之前通过 onclick 绑的函数,而 addEventListener 不会。混用容易混乱,统一用 addEventListener 最省心。

📖 小节

📝 作业

  1. 基础:创建一个按钮,用 addEventListener 绑定 click 事件,每次点击让按钮的宽度增加 10px。
  2. 进阶:实现一个键盘乐器——监听 keydown 事件,按 A/S/D/F/G 分别在页面上显示不同的音符名(Do/Re/Mi/Fa/Sol)。
  3. 挑战:用事件委托实现一个动态菜单——有一个 ul 列表和"添加项"按钮,新增的 li 点击后也能高亮显示(不需要给新 li 单独绑事件)。
  4. 附加:实现一个 input 事件实时搜索——输入框打字时,下方列表只显示包含输入文字的项。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏