切换主题
浏览器事件简介
浏览器事件是用户与网页交互时发生的各种动作,如点击、滚动、按键等。事件系统允许我们监听这些动作并作出响应。
事件类型
- 鼠标事件:click、dblclick、mouseover、mouseout 等
- 键盘事件:keydown、keyup、keypress
- 表单事件:submit、change、input、focus、blur
- 文档事件:load、DOMContentLoaded、unload
- 窗口事件:resize、scroll
- 触摸事件:touchstart、touchmove、touchend
- 拖拽事件:dragstart、drag、drop
冒泡和捕获
事件传播机制包含两个阶段:
事件冒泡
事件从最具体的元素(目标元素)开始触发,然后逐级向上传播到较为不具体的节点。
javascript
// 冒泡示例
document.body.addEventListener('click', function() {
console.log('body 被点击');
});
div.addEventListener('click', function() {
console.log('div 被点击');
});
button.addEventListener('click', function() {
console.log('button 被点击');
});
// 点击 button 时,输出顺序:
// 1. button 被点击
// 2. div 被点击
// 3. body 被点击
事件捕获
事件从最不具体的节点开始触发,直到最具体的节点。
javascript
// 捕获示例
document.body.addEventListener('click', function() {
console.log('body 捕获到点击');
}, true);
div.addEventListener('click', function() {
console.log('div 捕获到点击');
}, true);
button.addEventListener('click', function() {
console.log('button 捕获到点击');
}, true);
// 点击 button 时,输出顺序:
// 1. body 捕获到点击
// 2. div 捕获到点击
// 3. button 捕获到点击
事件委托
事件委托是一种利用事件冒泡的技术,将事件监听器添加到父元素上,而不是为每个子元素单独添加。
优点
- 减少内存占用
- 动态元素自动获得事件处理
- 提高性能
- 简化代码
示例
javascript
// 不好的做法
const items = document.querySelectorAll('.item');
items.forEach(item => {
item.addEventListener('click', function() {
console.log(this.textContent);
});
});
// 好的做法:使用事件委托
const container = document.querySelector('.container');
container.addEventListener('click', function(event) {
if (event.target.matches('.item')) {
console.log(event.target.textContent);
}
});
浏览器默认行为
浏览器为某些事件提供了默认行为,如点击链接会跳转、提交表单会刷新页面等。
阻止默认行为
javascript
// 阻止链接跳转
link.addEventListener('click', function(event) {
event.preventDefault();
});
// 阻止表单提交
form.addEventListener('submit', function(event) {
event.preventDefault();
});
// 阻止右键菜单
document.addEventListener('contextmenu', function(event) {
event.preventDefault();
});
阻止事件传播
javascript
// 阻止事件冒泡
element.addEventListener('click', function(event) {
event.stopPropagation();
});
// 阻止事件捕获
element.addEventListener('click', function(event) {
event.stopPropagation();
}, true);
创建自定义事件
JavaScript 允许创建和触发自定义事件,这对于组件间通信很有用。
基本用法
javascript
// 创建自定义事件
const event = new CustomEvent('customEvent', {
detail: { message: '自定义事件数据' },
bubbles: true,
cancelable: true
});
// 触发事件
element.dispatchEvent(event);
// 监听自定义事件
element.addEventListener('customEvent', function(event) {
console.log(event.detail.message);
});
事件选项
javascript
const event = new CustomEvent('customEvent', {
detail: {}, // 事件携带的数据
bubbles: true, // 是否冒泡
cancelable: true, // 是否可以取消
composed: true // 是否可以穿过 Shadow DOM
});
JavaScript 事件
JavaScript 事件是与网页交互过程中发生的事情,如点击、加载、鼠标移动等。通过事件处理,可以响应用户操作并执行相应的 JavaScript 代码。
事件基础
1. 事件注册
有三种方式可以注册事件:
a. HTML 属性(不推荐)
html
<button onclick="alert('点击了按钮')">点击我</button>
b. DOM 属性
javascript
const button = document.querySelector('button');
button.onclick = function() {
alert('点击了按钮');
};
c. 事件监听器(推荐)
javascript
const button = document.querySelector('button');
button.addEventListener('click', function() {
alert('点击了按钮');
});
2. 移除事件监听器
javascript
function handleClick() {
console.log('按钮被点击');
}
button.addEventListener('click', handleClick);
// 移除事件
button.removeEventListener('click', handleClick);
事件对象
当事件被触发时,会自动创建一个事件对象,包含事件相关信息。
javascript
button.addEventListener('click', function(event) {
// event 是事件对象
console.log(event.type); // 'click'
console.log(event.target); // 事件触发的元素
console.log(event.currentTarget); // 事件处理程序附加的元素
});
常用事件对象属性和方法
javascript
element.addEventListener('click', function(event) {
// 阻止默认行为
event.preventDefault();
// 阻止事件冒泡
event.stopPropagation();
// 获取鼠标坐标(相对于视口)
console.log(event.clientX, event.clientY);
// 获取鼠标坐标(相对于文档)
console.log(event.pageX, event.pageY);
// 获取按键信息
console.log(event.key, event.code);
});
事件传播
事件传播有三个阶段:
- 捕获阶段:事件从 Window 对象向下传递到目标元素
- 目标阶段:事件到达目标元素
- 冒泡阶段:事件从目标元素向上冒泡到 Window 对象
事件冒泡
javascript
// 子元素事件处理
child.addEventListener('click', function(event) {
console.log('子元素被点击');
});
// 父元素事件处理
parent.addEventListener('click', function(event) {
console.log('父元素感知到点击'); // 点击子元素时也会触发
});
事件捕获
javascript
// 第三个参数设为 true 启用捕获
parent.addEventListener('click', function(event) {
console.log('捕获阶段父元素感知到点击');
}, true);
child.addEventListener('click', function(event) {
console.log('子元素被点击');
});
事件委托
利用事件冒泡,将事件处理程序添加到父元素上,处理多个子元素的事件。
javascript
// 不好的做法:为每个列表项添加事件
const items = document.querySelectorAll('li');
items.forEach(item => {
item.addEventListener('click', function() {
console.log(this.textContent);
});
});
// 好的做法:使用事件委托
const list = document.querySelector('ul');
list.addEventListener('click', function(event) {
if (event.target.tagName === 'LI') {
console.log(event.target.textContent);
}
});
常见事件类型
1. 鼠标事件
javascript
element.addEventListener('click', handleClick); // 点击
element.addEventListener('dblclick', handleDblClick); // 双击
element.addEventListener('mouseover', handleMouseOver); // 鼠标悬停
element.addEventListener('mouseout', handleMouseOut); // 鼠标移出
element.addEventListener('mousemove', handleMouseMove); // 鼠标移动
2. 键盘事件
javascript
document.addEventListener('keydown', function(event) {
console.log(`键盘按下: ${event.key}`);
});
document.addEventListener('keyup', function(event) {
console.log(`键盘释放: ${event.key}`);
});
document.addEventListener('keypress', function(event) {
console.log(`键盘按压: ${event.key}`);
});
3. 表单事件
javascript
const form = document.querySelector('form');
// 表单提交
form.addEventListener('submit', function(event) {
event.preventDefault(); // 阻止表单默认提交
console.log('表单提交');
});
// 输入变化
const input = document.querySelector('input');
input.addEventListener('input', function(event) {
console.log('输入内容:', event.target.value);
});
// 失去焦点
input.addEventListener('blur', function() {
validateInput(this.value);
});
// 获得焦点
input.addEventListener('focus', function() {
this.classList.add('active');
});
4. 文档/窗口事件
javascript
// 页面加载完成
window.addEventListener('load', function() {
console.log('页面及所有资源加载完成');
});
// DOM 内容加载完成(不等待图片等资源)
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM 加载完成');
});
// 窗口大小改变
window.addEventListener('resize', function() {
console.log(`窗口大小: ${window.innerWidth}x${window.innerHeight}`);
});
// 滚动事件
window.addEventListener('scroll', function() {
console.log(`滚动位置: ${window.scrollX}, ${window.scrollY}`);
});
自定义事件
创建和触发自定义事件。
javascript
// 创建自定义事件
const customEvent = new CustomEvent('userLogin', {
detail: { userId: 123, username: 'john' },
bubbles: true,
cancelable: true
});
// 触发自定义事件
document.dispatchEvent(customEvent);
// 监听自定义事件
document.addEventListener('userLogin', function(event) {
console.log(`用户 ${event.detail.username} 登录成功`);
});
事件性能优化
1. 使用事件委托
javascript
// 不好的做法
document.querySelectorAll('.item').forEach(item => {
item.addEventListener('click', handleClick);
});
// 好的做法
document.querySelector('.container').addEventListener('click', function(event) {
if (event.target.matches('.item')) {
handleClick(event);
}
});
2. 防抖(Debounce)和节流(Throttle)
javascript
// 防抖
function debounce(fn, delay) {
let timer = null;
return function() {
if (timer) clearTimeout(timer);
const context = this;
const args = arguments;
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}
// 使用防抖处理输入
const debouncedInput = debounce(function(event) {
console.log('处理输入:', event.target.value);
}, 300);
input.addEventListener('input', debouncedInput);
// 节流
function throttle(fn, delay) {
let lastCall = 0;
return function() {
const now = new Date().getTime();
if (now - lastCall < delay) return;
lastCall = now;
return fn.apply(this, arguments);
};
}
// 使用节流处理滚动
const throttledScroll = throttle(function() {
console.log('处理滚动');
}, 100);
window.addEventListener('scroll', throttledScroll);
3. 被动事件监听
javascript
// 使用 passive 选项提高滚动性能
document.addEventListener('scroll', function() {
console.log('滚动');
}, { passive: true });
最佳实践
- 使用
addEventListener
而不是 HTML 属性或 DOM 属性 - 正确移除不再需要的事件监听器
- 使用事件委托处理多元素事件
- 避免在高频事件(scroll, resize, mousemove)中执行复杂操作
- 使用防抖和节流控制事件触发频率
- 使用被动事件监听器提高性能
- 避免阻止事件传播,除非有明确需求
- 事件处理函数保持简洁,逻辑分离