JavaScript 常用事件大全:从基础到实战应用
haoteby 2025-09-18 19:12 1 浏览
JavaScript 事件是交互开发的核心,它允许代码响应用户操作、浏览器行为或文档变化。本文将从基础概念出发,分类梳理常用事件,并结合实战场景说明其应用,帮助你系统掌握事件编程。
一、事件基础:核心概念与绑定方式
在学习具体事件前,需先理解事件的核心逻辑 ——“谁在什么情况下执行什么操作”。
1. 事件三要素
任何事件都包含三个核心部分,缺一不可:
- 事件源:触发事件的元素(如按钮、输入框、窗口)。
- 事件类型:事件的具体类别(如 “点击”“键盘按下”“页面加载”)。
- 事件处理程序:事件触发时执行的函数(可通过匿名函数、命名函数定义)。
2. 事件流(Event Flow)
当事件触发时,浏览器会按特定顺序传播事件,即事件流,分为三个阶段(DOM2 级规范):
- 捕获阶段:事件从最顶层的document向下传播到事件源的父元素。
- 目标阶段:事件到达事件源本身。
- 冒泡阶段:事件从事件源向上传播回document(大部分日常开发用冒泡阶段)。
示例:点击按钮时,事件流顺序为 document → html → body → 按钮父元素 → 按钮(目标)→ 按钮父元素 → body → html → document。
3. 事件绑定方式
常用的事件绑定方式有三种,各有优缺点:
绑定方式 | 语法示例 | 特点 |
HTML 内联绑定 | <button onclick="handleClick()"> | 耦合 HTML 与 JS,维护性差,不推荐 |
DOM0 级绑定 | btn.onclick = handleClick | 简单直观,仅支持冒泡,同一事件只能绑定一个函数 |
DOM2 级绑定 | btn.addEventListener('click', handleClick) | 支持捕获 / 冒泡,可绑定多个函数,推荐使用 |
解绑注意:DOM0 级用 btn.onclick = null,DOM2 级,需用 removeEventListener(且函数必须是命名函数,不能是匿名函数)。
二、常用事件分类与应用场景
按触发场景将事件分为 6 大类,每类包含核心事件、触发时机及简单示例。
1. 鼠标事件(Mouse Events)
最常用的交互事件,响应鼠标操作(点击、移动、滚轮等)。
事件名称 | 触发时机 | 示例代码 |
click | 鼠标左键单击(松开时触发) | btn.addEventListener('click', () => alert('按钮被点击')) |
dblclick | 鼠标左键双击 | div.addEventListener('dblclick', () => div.style.color = 'red') |
mousedown | 鼠标任意键按下(不区分左右键) | box.addEventListener('mousedown', () => box.style.border = '2px solid #000') |
mouseup | 鼠标任意键松开 | box.addEventListener('mouseup', () => box.style.border = 'none') |
mousemove | 鼠标在元素内移动(持续触发) | document.addEventListener('mousemove', (e) => console.log(坐标: \({e.clientX},\){e.clientY})) |
mouseover | 鼠标移入元素或其子元素(会冒泡) | nav.addEventListener('mouseover', (e) => e.target.style.backgroundColor = '#f5f5f5') |
mouseout | 鼠标移出元素或其子元素(会冒泡) | nav.addEventListener('mouseout', (e) => e.target.style.backgroundColor = 'transparent') |
mouseenter | 鼠标仅移入元素本身(不冒泡,性能更优) | card.addEventListener('mouseenter', () => card.style.transform = 'scale(1.05)') |
mouseleave | 鼠标仅移出元素本身(不冒泡) | card.addEventListener('mouseleave', () => card.style.transform = 'scale(1)') |
contextmenu | 鼠标右键单击(触发上下文菜单前) | document.addEventListener('contextmenu', (e) => { e.preventDefault(); alert('禁用右键菜单') }) |
wheel | 鼠标滚轮滚动(可获取滚动方向) | document.addEventListener('wheel', (e) => console.log('滚动方向:', e.deltaY > 0 ? '向下' : '向上')) |
关键区别:mouseover/mouseout 会因子元素触发冒泡,而 mouseenter/mouseleave 仅作用于元素本身,适合卡片、菜单等组件。
2. 键盘事件(Keyboard Events)
响应键盘操作,常用于快捷键、表单输入控制等场景。
事件名称 | 触发时机 | 示例代码 |
keydown | 键盘任意键按下(持续触发,支持所有键) | input.addEventListener('keydown', (e) => { if (e.key === 'Enter') submitForm() }) |
keyup | 键盘任意键松开(仅触发一次) | document.addEventListener('keyup', (e) => console.log('松开的键:', e.key)) |
keypress | 键盘字符键按下(仅支持可打印字符,逐步淘汰) | (建议用 keydown 替代,兼容性更好) |
常用属性:e.key(语义化键名,如 'Enter'/'Escape')、e.keyCode(键码,如 Enter 是 13,逐步淘汰)、e.ctrlKey/e.shiftKey(是否按住 Ctrl/Shift 键)。
3. 表单事件(Form Events)
专门用于表单元素(
input/select/textarea/form),处理输入、提交等行为。
事件名称 | 触发时机 | 示例代码 |
input | 表单元素值实时变化(输入、粘贴、删除等) |
|
change | 表单元素值确认变化(失去焦点或选择后) | select.addEventListener('change', (e) => console.log('选中的值:', e.target.value)) |
blur | 元素失去焦点(点击外部或按 Tab 键) |
|
focus | 元素获得焦点(点击或按 Tab 键) | usernameInput.addEventListener('focus', () => usernameInput.style.border = '2px solid #4CAF50') |
submit | 表单提交(点击提交按钮或按 Enter) | form.addEventListener('submit', (e) => { e.preventDefault(); // 阻止默认提交,执行自定义验证 }) |
reset | 表单重置(点击重置按钮) | form.addEventListener('reset', () => alert('表单已重置')) |
实战重点:input 用于实时验证,submit 必须阻止默认行为(e.preventDefault())后再执行自定义逻辑,避免页面刷新。
4. 文档 / 窗口事件(Document/Window Events)
响应文档加载、窗口大小变化、滚动等浏览器级行为。
事件名称 | 触发时机 | 示例代码 |
DOMContentLoaded | DOM 树加载完成(无需等待图片、CSS 等资源) | document.addEventListener('DOMContentLoaded', () => { console.log('DOM已就绪,可以操作元素') }) |
load | 整个页面(DOM + 图片 + CSS 等)加载完成 | window.addEventListener('load', () => { console.log('页面所有资源已加载') }) |
resize | 窗口大小改变时(持续触发) | window.addEventListener('resize', () => { console.log('窗口宽度:', window.innerWidth) }) |
scroll | 页面或元素滚动时(持续触发) | window.addEventListener('scroll', () => { if (window.scrollY > 500) showBackToTopBtn() }) |
beforeunload | 页面关闭 / 刷新前(用于提示用户保存) | window.addEventListener('beforeunload', (e) => { e.returnValue = '确定离开吗?未保存的内容将丢失'; return '确定离开吗?' }) |
unload | 页面关闭时(仅用于简单清理,不推荐复杂操作) | window.addEventListener('unload', () => { // 发送统计数据(可能丢失,建议用beacon API) }) |
关键区别:DOMContentLoaded 比 load 触发更早,是操作 DOM 的最佳时机;scroll/resize 持续触发时需加节流优化(如每 100ms 执行一次),避免性能问题。
5. 触摸事件(Touch Events)
针对移动端设备,响应手指触摸操作(替代鼠标事件,避免延迟)。
事件名称 | 触发时机 | 示例代码 |
touchstart | 手指触摸屏幕时 | slide.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; }) |
touchmove | 手指在屏幕上滑动时(持续触发) | slide.addEventListener('touchmove', (e) => { moveX = e.touches[0].clientX; if (moveX - startX > 50) nextSlide(); }) |
touchend | 手指离开屏幕时 | slide.addEventListener('touchend', () => { startX = 0; moveX = 0; }) |
touchcancel | 触摸被中断(如来电、弹窗) | slide.addEventListener('touchcancel', () => { // 重置触摸状态 }) |
注意:触摸事件会触发鼠标事件(如 touchstart 后触发 mousedown),需用 e.preventDefault() 阻止,或在 addEventListener 中加 passive: true 优化滚动性能(如 window.addEventListener('touchmove', handleMove, { passive: true }))。
6. UI 事件(UI Events)
响应元素 UI 状态变化,如元素显示 / 隐藏、焦点变化等(部分与其他分类重叠,重点列常用)。
事件名称 | 触发时机 | 示例代码 |
visibilitychange | 页面可见性变化(切换标签、最小化) | document.addEventListener('visibilitychange', () => { if (document.hidden) pauseVideo(); else playVideo(); }) |
focusin | 元素或其子元素获得焦点(冒泡,替代focus) | form.addEventListener('focusin', (e) => e.target.style.border = '2px solid #4CAF50') |
focusout | 元素或其子元素失去焦点(冒泡,替代blur) | form.addEventListener('focusout', (e) => e.target.style.border = '1px solid #ccc') |
三、实战应用:从基础到进阶
掌握事件的核心是 “灵活运用”,以下是 3 个高频实战场景,覆盖事件委托、事件对象、多事件协作。
1. 场景 1:事件委托(优化动态列表)
问题:动态添加的列表项(如购物车商品)无法绑定事件,直接给每个项绑定会浪费性能。
解决方案:利用事件冒泡,将事件绑定到父元素(如列表容器),通过 e.target 定位触发元素。
<ul id="todoList">
<li>学习事件委托</li>
<li>完成实战示例</li>
</ul>
<button id="addTodo">添加任务</button>
<script>
const todoList = document.getElementById('todoList');
const addTodo = document.getElementById('addTodo');
// 1. 委托事件到父元素
todoList.addEventListener('click', (e) => {
// 确认触发元素是列表项(避免点击空白处触发)
if (e.target.tagName === 'LI') {
e.target.style.textDecoration = 'line-through'; // 标记完成
}
});
// 2. 动态添加列表项
addTodo.addEventListener('click', () => {
const li = document.createElement('li');
li.textContent = '新任务:' + new Date().getSeconds();
todoList.appendChild(li);
});
</script>
优势:只需绑定 1 次事件,支持任意动态元素,减少内存占用。
2. 场景 2:表单验证(多事件协作)
需求:实时验证用户名(长度≥3)、密码(含数字),提交时阻止无效表单。
<form id="loginForm">
<div>
<label>用户名:</label>
<input type="text" id="username" name="username">
<span class="error" id="usernameError"></span>
</div>
<div>
<label>密码:</label>
<input type="password" id="password" name="password">
<span class="error" id="passwordError"></span>
</div>
<button type="submit">登录</button>
</form>
<script>
const form = document.getElementById('loginForm');
const username = document.getElementById('username');
const password = document.getElementById('password');
const usernameError = document.getElementById('usernameError');
const passwordError = document.getElementById('passwordError');
// 1. 实时验证用户名(input事件)
username.addEventListener('input', (e) => {
const value = e.target.value.trim();
if (value.length < 3) {
usernameError.textContent = '用户名至少3个字符';
usernameError.style.color = 'red';
} else {
usernameError.textContent = '';
}
});
// 2. 实时验证密码(blur事件,失去焦点时验证)
password.addEventListener('blur', (e) => {
const value = e.target.value;
if (!/\d/.test(value)) { // 正则判断是否含数字
passwordError.textContent = '密码必须包含数字';
passwordError.style.color = 'red';
} else {
passwordError.textContent = '';
}
});
// 3. 提交表单(submit事件,阻止默认行为)
form.addEventListener('submit', (e) => {
e.preventDefault(); // 阻止页面刷新
// 二次验证(避免用户跳过实时验证直接提交)
const isUsernameValid = username.value.trim().length >= 3;
const isPasswordValid = /\d/.test(password.value);
if (isUsernameValid && isPasswordValid) {
alert('表单验证通过,正在提交...');
// 这里执行AJAX提交逻辑
} else {
alert('请修正表单错误后重试');
}
});
</script>
3. 场景 3:拖拽功能(鼠标事件协作)
需求:实现一个可拖拽的 div,支持鼠标按下拖动、松开停止。
<div id="dragBox" style="width: 100px; height: 100px; background: #4CAF50; position: absolute; cursor: move;"></div>
<script>
const dragBox = document.getElementById('dragBox');
let isDragging = false; // 标记是否正在拖拽
let startX, startY, offsetX, offsetY; // 初始位置和偏移量
// 1. 鼠标按下:记录初始位置
dragBox.addEventListener('mousedown', (e) => {
isDragging = true;
// 获取鼠标相对于盒子的偏移量(避免鼠标在盒子内不同位置导致跳动)
startX = e.clientX;
startY = e.clientY;
offsetX = startX - dragBox.offsetLeft;
offsetY = startY - dragBox.offsetTop;
dragBox.style.opacity = '0.8'; // 拖拽时半透明
});
// 2. 鼠标移动:更新盒子位置(绑定到document,避免鼠标移出盒子后停止)
document.addEventListener('mousemove', (e) => {
if (!isDragging) return; // 未拖拽时不执行
// 计算盒子新位置
const newLeft = e.clientX - offsetX;
const newTop = e.clientY - offsetY;
// 限制盒子在窗口内(可选)
const maxLeft = window.innerWidth - dragBox.offsetWidth;
const maxTop = window.innerHeight - dragBox.offsetHeight;
const finalLeft = Math.max(0, Math.min(newLeft, maxLeft));
const finalTop = Math.max(0, Math.min(newTop, maxTop));
// 更新位置
dragBox.style.left = finalLeft + 'px';
dragBox.style.top = finalTop + 'px';
});
// 3. 鼠标松开:停止拖拽
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
dragBox.style.opacity = '1'; // 恢复不透明
}
});
</script>
四、注意事项与性能优化
- 阻止不必要的冒泡 / 默认行为:冒泡:用 e.stopPropagation() 或 e.stopImmediatePropagation()(阻止后续处理函数)。默认行为:用 e.preventDefault()(如阻止表单提交、链接跳转),但注意不要滥用(如阻止页面滚动)。
- 优化高频触发事件:
scroll/resize/mousemove/touchmove 会持续触发,需用节流(throttle) 或防抖(debounce) 控制执行频率:
// 节流示例:每100ms执行一次
function throttle(fn, delay = 100) {
let lastTime = 0;
return (...args) => {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
}
};
}
// 使用
window.addEventListener('scroll', throttle(() => {
console.log('滚动位置:', window.scrollY);
}));
- 及时解绑事件:
单页应用(SPA)或动态元素删除时,需解绑事件避免内存泄漏:
const handleClick = () => alert('点击');
btn.addEventListener('click', handleClick);
// 解绑(必须用同一命名函数)
btn.removeEventListener('click', handleClick);
- 移动端优先考虑触摸事件:
鼠标事件在移动端有 300ms 延迟(历史兼容问题),推荐用 touchstart/touchmove/touchend,或在 HTML 头部加 <meta name="viewport" content="width=device-width"> 消除延迟。
总结
JavaScript 事件是交互开发的基石,掌握 “事件分类→事件对象→事件流→实战场景” 的逻辑链,能让你灵活应对各类需求。重点记住:
- 优先用 addEventListener 绑定事件,支持多处理函数和捕获 / 冒泡控制;
- 动态元素用事件委托优化;
- 高频事件用节流 / 防抖提升性能;
- 移动端优先用触摸事件,避免延迟。
结合本文的事件列表和实战示例,可快速定位并解决开发中的交互问题。
相关推荐
- 如何随时清理浏览器缓存_清理浏览器缓存怎么弄
-
想随时清理浏览器缓存吗?Cookieformac版是Macos上一款浏览器缓存清理工具,所有的浏览器Cookie,本地存储数据,HTML5数据库,FlashCookie,Silverlight,...
- Luminati代理动态IP教程指南配置代理VMLogin中文版反指纹浏览器
-
介绍如何使用在VMLogin中文版设置Luminati代理。首先下载VMLogin中文版反指纹浏览器(https://cn.vmlogin.com)对于刚接触Luminati动态ip的朋友,是不是不懂...
- mac清除工具分享,解除您在安全方面的后顾之忧
-
想要永久的安全的处理掉重要数据,删除是之一,使用今天小编分享的mac清除工具,为您的操作再增一层“保护”,小伙伴慎用哟,一旦使用就不可以恢复咯,来吧一起看看吧~mac清除工具分享,解除您在安全方面的后...
- 取代cookie的网站追踪技术:”帆布指纹识别”
-
【前言】一般情况下,网站或者广告联盟都会非常想要一种技术方式可以在网络上精确定位到每一个个体,这样可以通过收集这些个体的数据,通过分析后更加精准的去推送广告(精准化营销)或其他有针对性的一些活动。Co...
- 辅助上网为啥会被抛弃 曲奇(Cookie)虽甜但有毒
-
近期有个小新闻,大概很多小伙伴都没有注意到,那就是谷歌Chrome浏览器要弃用Cookie了!说到Cookie功能,很多小伙伴大概觉得不怎么熟悉,有可能还不如前一段时间被弃用的Flash“出名”,但它...
- 浏览器指纹是什么?浏览器指纹包括哪些信息
-
本文关键词:浏览器指纹、指纹浏览器、浏览器指纹信息、指纹浏览器原理什么是浏览器指纹?浏览器指纹是指浏览器的各种信息,当我们访问其他网站时,即使是在匿名的模式下,这些信息也可以帮助网站识别我们的身份。...
- 那些通用清除软件不曾注意的秘密_清理不常用的应用软件
-
系统清理就像卫生检查前的大扫除,即使你使出吃奶的劲儿把一切可能的地方都打扫过,还会留下边边角角的遗漏。随着大家电脑安全意识的提高,越来越多的朋友开始关注自己的电脑安全,也知道安装360系列软件来"武装...
- 「网络安全宣传周」这些安全上网小知识你要知道!
-
小布说:互联网改变了人们的衣食住行,但与之伴生的网络安全威胁也不容忽视。近些年来,风靡全球的勒索病毒、时有发生的电信诈骗、防不胜防的个人信息泄露时时刻刻都威胁着我们的生活。9月18日-24日是第四届...
- TypeScript 终极初学者指南_typescript 进阶
-
在过去的几年里TypeScript变得越来越流行,现在许多工作都要求开发人员了解TypeScript...
- jQuery知识一览_jquery的认识和使用
-
一、概览jQuery官网:https://jquery.com/jQuery是一个高效、轻量并且功能丰富的js库。核心在于查询query。...
- 我的第一个Electron应用_electronmy
-
hello,好久不见,最近笔者花了几天时间入门Electron,然后做了一个非常简单的应用,本文就来给各位分享一下过程,Electron大佬请随意~笔者开源了一个Web思维导图,虽然借助showSav...
- HTML5 之拖放(Drag 和 Drop)_html拖放api
-
简介拖放是一种常见的特性,即抓取对象以后拖到另一个位置。在HTML5中,拖放是标准的一部分,任何元素都能够拖放。先点击一个小例子:在用户开始拖动<p>元素时执行JavaScrip...
- 如何用JavaScript判断输入值是数字还是字母?
-
在日常开发中,我们有时候需要判断用户输入的是数字还是字母。本文将介绍如何用JavaScript实现这一功能。检查输入值是否是数字或字母...
- 图形编辑器开发:快捷键的管理_图形编辑工具
-
大家好,我是前端西瓜哥。...
- 浏览器原生剪贴板:原来它能这样读取用户截图!
-
当我们使用GitHub时,会发现Ctrl+V就能直接读取用户剪贴板图片进行粘贴,那么它是如何工作的?安全性如何?...