事件处理

事件是浏览器或用户与网页交互时发生的动作,如点击、滚动、按键等。JavaScript可以通过事件处理来响应用户操作。

事件流

事件流描述了事件在DOM树中传播的过程,主要有两种模型:

冒泡模型

事件从触发元素开始,逐级向上传播到文档根节点:

text
元素 → 父元素 → ... → body → html → document

捕获模型

事件从文档根节点开始,逐级向下传播到触发元素:

text
document → html → body → ... → 父元素 → 元素

事件处理方式

1. HTML属性方式

直接在HTML标签中添加事件属性:

html
<button onclick="handleClick()">点击我</button>

<script>
function handleClick() {
  alert('按钮被点击了');
}
</script>

2. DOM属性方式

通过JavaScript设置元素的事件属性:

javascript
const button = document.getElementById('myButton');
button.onclick = function() {
  alert('按钮被点击了');
};

// 移除事件处理程序
button.onclick = null;

3. addEventListener方法

推荐使用的方式,可以添加多个事件处理程序:

javascript
const button = document.getElementById('myButton');

// 添加事件监听器
button.addEventListener('click', function() {
  alert('按钮被点击了');
});

// 添加另一个事件监听器
button.addEventListener('click', function() {
  console.log('按钮点击事件被记录');
});

// 移除事件监听器(需要使用命名函数)
function handleClick() {
  alert('点击处理');
}
button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick);

捕获与冒泡

javascript
const parent = document.getElementById('parent');
const child = document.getElementById('child');

// 捕获阶段执行(第三个参数为true)
parent.addEventListener('click', function() {
  console.log('父元素捕获');
}, true);

// 冒泡阶段执行(默认,第三个参数为false)
parent.addEventListener('click', function() {
  console.log('父元素冒泡');
}, false);

child.addEventListener('click', function() {
  console.log('子元素冒泡');
});

// 点击子元素时的执行顺序:
// 1. 父元素捕获
// 2. 子元素冒泡
// 3. 父元素冒泡

事件对象

事件处理程序会接收一个事件对象作为参数,包含事件的详细信息:

javascript
const button = document.getElementById('myButton');
button.addEventListener('click', function(event) {
  console.log(event.type); // 事件类型:"click"
  console.log(event.target); // 事件目标元素:按钮
  console.log(event.currentTarget); // 当前处理事件的元素:按钮
  console.log(event.clientX, event.clientY); // 点击位置相对于浏览器窗口
  console.log(event.pageX, event.pageY); // 点击位置相对于文档
  console.log(event.screenX, event.screenY); // 点击位置相对于屏幕
});

事件类型

鼠标事件

javascript
// 点击事件
element.addEventListener('click', handler);
element.addEventListener('dblclick', handler); // 双击

// 鼠标移动
element.addEventListener('mousedown', handler); // 鼠标按下
element.addEventListener('mouseup', handler); // 鼠标释放
element.addEventListener('mousemove', handler); // 鼠标移动
element.addEventListener('mouseover', handler); // 鼠标进入
element.addEventListener('mouseout', handler); // 鼠标离开
element.addEventListener('mouseenter', handler); // 鼠标进入(不冒泡)
element.addEventListener('mouseleave', handler); // 鼠标离开(不冒泡)

键盘事件

javascript
document.addEventListener('keydown', handler); // 按键按下
document.addEventListener('keyup', handler); // 按键释放
document.addEventListener('keypress', handler); // 按键按下并释放

// 键盘事件对象
document.addEventListener('keydown', function(event) {
  console.log(event.key); // 按键名称:"a", "Enter", "Shift"
  console.log(event.keyCode); // 按键代码(数字)
  console.log(event.ctrlKey); // Ctrl键是否按下
  console.log(event.shiftKey); // Shift键是否按下
  console.log(event.altKey); // Alt键是否按下
});

表单事件

javascript
const form = document.getElementById('myForm');
const input = document.getElementById('myInput');

form.addEventListener('submit', function(event) {
  event.preventDefault(); // 阻止表单默认提交行为
  // 表单处理逻辑
});

input.addEventListener('input', function() {
  console.log('输入内容:', this.value);
});

input.addEventListener('change', function() {
  console.log('输入内容已更改:', this.value);
});

input.addEventListener('focus', function() {
  console.log('输入框获得焦点');
});

input.addEventListener('blur', function() {
  console.log('输入框失去焦点');
});

窗口事件

javascript
// 页面加载完成
window.addEventListener('load', function() {
  console.log('页面加载完成');
});

// DOM加载完成
document.addEventListener('DOMContentLoaded', function() {
  console.log('DOM加载完成');
});

// 窗口大小改变
window.addEventListener('resize', function() {
  console.log('窗口大小改变');
});

// 窗口滚动
window.addEventListener('scroll', function() {
  console.log('窗口滚动');
});

事件委托

利用事件冒泡原理,在父元素上监听事件,处理子元素的事件:

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

<script>
const list = document.getElementById('myList');
list.addEventListener('click', function(event) {
  if (event.target.tagName === 'LI') {
    console.log('点击了项目:', event.target.textContent);
  }
});
</script>

事件委托的优点:

  • 减少事件监听器的数量
  • 动态添加的子元素也能响应事件

事件阻止

阻止默认行为

javascript
const link = document.getElementById('myLink');
link.addEventListener('click', function(event) {
  event.preventDefault(); // 阻止链接跳转
  console.log('链接被点击,但不跳转');
});

阻止事件冒泡

javascript
const child = document.getElementById('child');
child.addEventListener('click', function(event) {
  event.stopPropagation(); // 阻止事件冒泡
  console.log('子元素被点击,事件不会冒泡到父元素');
});

const parent = document.getElementById('parent');
parent.addEventListener('click', function() {
  console.log('父元素被点击'); // 点击子元素时不会执行
});

阻止其他事件处理程序

javascript
const button = document.getElementById('myButton');

button.addEventListener('click', function(event) {
  console.log('第一个处理程序');
  event.stopImmediatePropagation(); // 阻止其他处理程序
});

button.addEventListener('click', function() {
  console.log('第二个处理程序'); // 不会执行
});

自定义事件

创建和触发自定义事件:

javascript
// 创建自定义事件
const customEvent = new Event('myCustomEvent', {
  bubbles: true, // 是否冒泡
  cancelable: true // 是否可取消
});

// 添加自定义事件监听器
const element = document.getElementById('myElement');
element.addEventListener('myCustomEvent', function(event) {
  console.log('自定义事件被触发:', event.type);
});

// 触发自定义事件
element.dispatchEvent(customEvent);

// 创建带数据的自定义事件
const customEventWithData = new CustomEvent('myEventWithData', {
  detail: { message: '自定义事件数据' }
});

element.addEventListener('myEventWithData', function(event) {
  console.log('事件数据:', event.detail.message);
});

element.dispatchEvent(customEventWithData);

学习资源


继续学习:正则表达式

最后更新:2026-02-08