资讯中心

JavaScript 事件驱动编程实战:The JavaScript Way 之 DOM 事件处理完全指南

📅 2026/9/27 11:14:20
JavaScript 事件驱动编程实战:The JavaScript Way 之 DOM 事件处理完全指南
教程文档【免费下载链接】thejswayThe JavaScript Way book项目地址https://gitcode.com/gh_mirrors/th/thejsway点击查看免费下载本篇指南基于开源书籍《The JavaScript Way》manuscript/chapter16.md的 React to events 章节系统讲解如何在浏览器中用 JavaScript 响应键盘、鼠标、页面加载等用户动作从addEventListener()/removeEventListener()的监听器机制到Event对象的核心属性再到事件传播、stopPropagation()与preventDefault()的高级控制能力。读完本文你将掌握事件驱动编程的完整方法论并能独立实现按钮点击计数、按键改色、动态列表与交互式问答等典型页面功能。事件驱动编程从顺序执行到用户响应在此之前你的 JavaScript 代码总是在页面加载后从头到尾顺序执行唯一的用户交互是prompt()的数据输入。要让网页真正活起来程序必须响应用户的动作——点击按钮、填写表单、按下按键等等。此时语句的执行顺序不再预先确定而是取决于用户行为用户动作会触发事件event你可以编写 JavaScript 代码来**处理handle**这些事件。这种编写程序的方式被称为事件驱动编程event-driven programming它广泛用于用户界面更一般地任何需要与用户交互的程序都会采用这种模式。DOM 事件模型正是浏览器提供给前端开发者的事件驱动编程接口。第一个示例只需两段代码就能看到事件驱动的效果。首先是 HTML 起点button idmyButtonClick me!/button配套的 JavaScript 代码const showMessage () { alert(Hello!); }; // Access the button const buttonElement document.getElementById(myButton); // Listen to the click event buttonElement.addEventListener(click, showMessage);点击网页上的按钮浏览器就会弹出一个Hello!提示框。这个例子揭示了事件编程的三个基本步骤用getElementById()等 DOM 查询方法拿到目标元素元素选择方法详见 manuscript/chapter14.md、定义一个处理函数、再通过addEventListener()把两者绑定起来。事件监听器的添加与移除addEventListener()注册事件处理函数在 DOM 元素上调用addEventListener()方法可以为某个特定事件添加一个处理器handler。它接收两个参数事件类型event type和关联的处理函数function。每当该类型的事件在该 DOM 元素上发生时这个函数就会被调用。上面的代码可以用**匿名函数anonymous function**改写得更简洁效果完全一致// Show a message when the user clicks on the button document.getElementById(myButton).addEventListener(click, () { alert(Hello!); });需要说明的是事件处理函数可以是普通函数、箭头函数或匿名函数只要它能在事件发生时被正确调用即可。从源码结构看《The JavaScript Way》全书均使用 ES2016 语法如箭头函数保持代码风格统一见 manuscript/index.md 对本书Standards-aligned特点的描述。removeEventListener()移除事件处理函数在某些特定场景下你可能希望元素不再响应某个事件。此时在元素上调用removeEventListener()并把当初处理该事件的那个函数作为参数传入即可// Remove the handler for the click event buttonElement.removeEventListener(click, showMessage);注意removeEventListener()只有在处理函数不是匿名函数时才能生效。因为移除时需要通过函数引用去匹配之前注册的处理器匿名函数没有可复用的引用因此无法被移除。这也是实践中建议为需要反复增删的事件处理器命名函数的原因。事件家族与 Event 对象四大事件类别浏览器中能被 DOM 元素触发的事件类型非常丰富主要有以下四大类类别典型示例键盘事件Keyboard events按下或释放某个按键鼠标事件Mouse events点击鼠标按钮、按下或释放鼠标按钮、悬停到某个区域窗口事件Window events页面加载或关闭、调整窗口大小、滚动表单事件Form events表单字段焦点变化、表单提交表单类事件在下一章得到全面展开focus/blur焦点获取与失去、change选择变化、input输入变化、submit表单提交等都在 manuscript/chapter17.md 中有完整示例它们是本章事件家族概念的直接延续。Event 对象事件的属性与方法每个事件都关联一个Event对象它既有属性properties——提供关于事件的信息也有方法methods——提供对事件施加影响的手段。这个对象可以被事件处理函数使用。Event对象的很多属性与事件类型相关但有些属性始终存在type返回事件类型target返回事件目标即作为事件来源的 DOM 元素。Event对象会作为参数传递给事件处理函数。下面的代码利用它向控制台输出事件类型与目标// Show event type and target when the user clicks on the button document.getElementById(myButton).addEventListener(click, e { console.log(Event type: ${e.type}, target: ${e.target}); });约定事件处理函数为Event对象选用的参数名通常是e或event。响应常见事件键盘事件keydown 与 keyup处理键盘按键最常用的方案是监听发生在网页DOMbody元素对应 JavaScript 全局变量document上的keydown与keyup事件。下面的例子在控制台输出按下按键对应的字符字符串值由事件关联的Event对象的key属性给出// Show the pressed key document.addEventListener(keyup, e { console.log(You pressed the ${e.key} key); });要同时管理按键的按下与释放就需要同时使用keydown和keyup两个事件。下面这个例子通过Event对象的type与keyCode属性输出事件类型和按键的编码// Show information on a keyboard event const keyboardInfo e { console.log(Keyboard event: ${e.type}, key: ${e.keyCode}); }; // Integrate this function into key press and release: document.addEventListener(keydown, keyboardInfo); document.addEventListener(keyup, keyboardInfo);这个运行结果也印证了键盘相关事件的触发顺序符合预期keydown→keyup。注意当一个按键被持续按住时keydown事件会被多次触发系统自动重复这是实现长按逻辑时需要留意的一个行为。鼠标事件click、mousedown 与 mouseup任何 DOM 元素上的鼠标点击都会产生一个click类型的事件。触屏设备智能手机、平板同样会为按钮关联click事件——只是由手指按压触发。click事件关联的Event对象有几个实用属性button告知使用的是哪个鼠标按钮clientX/clientY返回点击发生处的水平、垂直坐标坐标是相对于浏览器当前显示的页面区域定义的即相对坐标。下面的代码输出页面上所有点击事件的信息。事件处理函数mouseInfo()调用了另一个函数getMouseButton()用来把按钮编码转换为可读的名称// Return the name of the mouse button const getMouseButton code { let button unknown; switch (code) { case 0: // 0 is the code for the left mouse button button left; break; case 1: // 1 is the code for the middle mouse button button middle; break; case 2: // 2 is the code for the right button button right; break; } return button; }; // Show info about mouse event const mouseInfo e { console.log( Mouse event: ${e.type}, button: ${getMouseButton( e.button )}, X: ${e.clientX}, Y: ${e.clientY} ); }; // Add mouse click event listener document.addEventListener(click, mouseInfo);与键盘的keydown/keyup类似mousedown和mouseup事件用于处理鼠标按钮的按下与释放。下面的代码把同一个处理函数同时关联到这两个事件// Handle mouse button press and release document.addEventListener(mousedown, mouseInfo); document.addEventListener(mouseup, mouseInfo);从运行结果可以总结出鼠标相关事件的出现顺序mousedown→mouseup→click。也就是说一次完整的点击实际上会依次触发按下、释放、点击三个事件。页面加载load 事件网页的加载耗时取决于其复杂度。通过监听window对象代表浏览器窗口产生的load事件你可以精确获知页面何时完全加载完毕从而避免 JavaScript 在页面尚未加载完整时进行操作而引发混乱。下面的代码在页面完全加载后向控制台输出一条消息// Web page loading event window.addEventListener(load, e { console.log(The page has been loaded!); });在实际项目中等页面加载完再初始化是一个高频需求——比如在 manuscript/chapter17.md 的Character list练习中需要在页面加载时填充下拉列表load事件或其现代替代DOMContentLoaded正是这类初始化逻辑的挂载点。页面关闭beforeunload 事件有时你希望在页面关闭时做出响应。关闭发生在用户关闭显示页面的标签页或在标签页内导航到其他页面时。一个常见用例是向用户显示确认对话框。处理页面关闭通过在window对象上为beforeunload事件添加处理器来完成// Handle page closing window.addEventListener(beforeunload, e { const message Should you stay or should you go?; // Standard way of showing a confirmation dialog e.returnValue message; // Browser-specific way of showing a confirmation dialog return message; });在Event对象上设置returnValue属性是触发显示该值的确认对话框的标准方式。然而部分浏览器使用事件监听器的返回值来替代。上面的代码同时采用了两种技术以获得最大的浏览器兼容性。事件传播Event Propagation事件如何沿着 DOM 树冒泡DOM 将网页表示为一个节点层级结构。在子节点上触发的事件会接着在父节点上触发再到父节点的父节点一路向上直达 DOM 的根document变量。这一机制被称为事件传播event propagation。用下面的 HTML 代码创建一个小的 DOM 层级来观察传播p idparaA paragraph with a button idpropabutton/button inside/p配套的 JavaScript 代码在按钮、其父节点段落以及再上一级DOM 根上分别添加了click事件处理器// Click handler on the document document.addEventListener(click, e { console.log(Document handler); }); // Click handler on the paragraph document.getElementById(para).addEventListener(click, e { console.log(Paragraph handler); }); // Click handler on the button document.getElementById(propa).addEventListener(click, e { console.log(Button handler); });浏览器控制台的结果演示了click事件从按钮一路传播到 document 级别的过程你点击了按钮意味着你也点击了按钮所在的段落也就等于点击了整个文档。stopPropagation()中断事件传播但有时你只希望事件在按钮上触发一次而不想让它影响更大的层级。事件传播可以在任意时刻被中断——在事件处理函数中调用Event对象的stopPropagation()方法即可。这在避免同一事件被重复处理多次时非常有用。在按钮的点击处理器中加入一行代码就能阻止click事件继续向 DOM 树上层传播// Click handler on the button document.getElementById(propa).addEventListener(click, e { console.log(Button handler); e.stopPropagation(); // Stop the event propagation });对比传播示例与中断示例的两张控制台截图可以看出一旦调用stopPropagation()段落的 Paragraph handler 和 document 的 Document handler 都不会再输出——这正是事件传播被截断的直接证据。preventDefault()取消动作的默认行为页面上大多数用户动作都关联着默认行为default behavior点击链接会导航到链接目标右键点击会弹出上下文菜单等等。取消默认行为是可能的——只需在事件处理函数中调用Event对象的preventDefault()方法。用下面的 HTML 代码来演示这一能力pTime on your hands? a idforbidden hrefhttps://9gag.com/Click here/a/p// Handling clicking on the forbidden link document.getElementById(forbidden).addEventListener(click, e { alert(Yes... But no.); e.preventDefault(); // Cancels the default behavior });现在点击这个链接只会弹出一个对话框而不会导航到它的目标地址。preventDefault()是表单类页面的核心工具之一在 manuscript/chapter17.md 中处理submit事件时调用preventDefault()可以阻止表单数据被发送到服务器从而实现在浏览器端先行校验数据。章节串联事件驱动在《The JavaScript Way》中的位置从本书目录mkdocs.yml可以看出第 1219 章构成创建交互式网页Create interactive web pages模块本章 manuscript/chapter16.md 处于承上启下的位置前序知识manuscript/chapter14.md 讲解 DOM 遍历与元素选取getElementById、querySelector、getElementsByTagName等manuscript/chapter15.md 讲解 DOM 结构修改textContent、innerHTML、appendChild、style等——事件处理函数正是这些 DOM 操作能力的触发器后续延伸manuscript/chapter17.md 将本章的事件机制应用到表单场景focus/blur/change/input/submit并在此基础上引入正则表达式做输入校验编程范式本章确立的监听器 处理器模式贯穿全书剩余部分包括后续章节中的异步编程与网络请求场景。TL;DR本章核心结论速览通过编写与浏览器中事件绑定的 JavaScript 代码可以让网页变得可交互。可以处理的事件类型繁多每个事件类型都关联一个包含事件信息的Event对象。keypress、keydown和keyup事件用于响应键盘相关操作。click、mousedown和mouseup事件用于响应鼠标相关操作。页面加载与关闭分别对应load与beforeunload事件。事件会在 DOM 树中从其起源节点一路传播到文档根节点传播过程可通过stopPropagation()方法中断。在Event对象上调用preventDefault()方法可以取消触发该事件的动作所关联的默认行为。Coding time!四个实战练习本章末尾的四个练习覆盖了事件编程的典型应用形态建议在浏览器中逐一完成。下面是原题与解题要点。练习一计数点击Counting clicks起始 HTMLbutton idmyButtonClick me!/button pYou clicked on the button span idclickCount0/span times/p button iddeactivateDésactivate counting/button编写 JavaScript统计myButton按钮的点击次数并更新clickCount元素的显示deactivate按钮则停止计数。解题要点为myButton注册click监听器每次触发时递增计数并更新clickCount的textContentDOM 文本修改方法见 manuscript/chapter15.md为deactivate注册click监听器在其中调用removeEventListener()移除计数处理器——这正是本章移除事件监听器一节中处理器不能是匿名函数约束的用武之地计数函数必须具名才能被后续移除。练习二按键改色Changing colors起始 HTML 包含三段文本段落pPress the R (red), Y (yellow), G (green) or B (blue) key to change paragraph colors accordingly./p h1Paragraph 1/h1 divLorem ipsum dolor sit amet, consectetur adipiscing elit. Donec dignissim fringilla dapibus. Curabitur placerat efficitur molestie. Quisque quis consequat nibh. Aenean feugiat, eros eget aliquam vulputate, leo augue luctus lectus, non lobortis libero quam non sem. Aliquam sit amet tincidunt ex, mollis interdum massa./div h1Paragraph 2/h1 divVivamus at justo blandit, ornare leo id, vehicula urna. Fusce sed felis eget magna viverra feugiat eget nec orci. Duis non massa nibh. Aenean vehicula velit a magna lobortis tempor ut quis felis. Proin vitae dui a eros facilisis fringilla ut ut ante./div h1Paragraph 3/h1 divLorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sit amet pharetra massa. Nulla blandit erat nulla, et scelerisque libero varius ut. Praesent bibendum eu magna ullamcorper venenatis. Sed ut pellentesque leo. Sed ultrices sapien consequat odio posuere gravida./div编写 JavaScript根据用户按下的按键R、Y、G 或 B更新所有div标签的背景颜色。解题要点在document上监听keyup或keydown事件读取Event对象的key属性判断按下的键再用document.getElementsByTagName(div)或querySelectorAll选中所有div通过style.backgroundColor复合 CSS 属性的驼峰写法见 manuscript/chapter15.md统一改色。练习三甜点列表A dessert list起始 HTML 定义了一个当前为空的甜点列表h1My favourite desserts/h1 ul iddesserts /ul button idaddButtonAdd a dessert/button编写 JavaScript用户点击按钮时向列表中添加一种新甜点甜点名由用户决定。加分项实现点击某个甜点即可修改其名称。解题要点为addButton注册click监听器用prompt()获取用户输入的甜点名结合 manuscript/chapter15.md 的三步走createElement→ 设置属性 →appendChild向desserts列表追加li加分项则需要在每个列表项上再注册click监听器配合textContent修改名称。练习四交互式问答Interactive quiz起始 HTML 与 JavaScript 数据如下div idcontent/div// List of questions (statement answer) const questions [ { statement: 22?, answer: 22 4 }, { statement: In which year did Christopher Columbus discover America?, answer: 1492 }, { statement: What occurs twice in a lifetime, but once in every year, twice in a week but never in a day?, answer: The E letter } ];完善代码在页面的div元素中展示所有问题每个问题旁边放一个Show the answer按钮点击该按钮后按钮被替换为对应问题的答案。解题要点遍历questions数组为每个问题创建一个容器节点createElementappendChild写入问题文本并追加显示答案按钮为每个按钮注册click监听器在处理器中把按钮替换为答案文本——实现替换既可以结合本章的Event.target定位被点击的按钮也可以使用 manuscript/chapter15.md 中的replaceChild()或textContent直接改写节点内容。完成这四个练习后你就完整掌握了《The JavaScript Way》的事件编程核心监听器注册与移除、Event对象、键盘/鼠标/窗口事件、事件传播与默认行为控制。这些能力将直接支撑下一章的表单交互与输入校验实战。赞分享教程文档【免费下载链接】thejswayThe JavaScript Way book项目地址https://gitcode.com/gh_mirrors/th/thejsway点击查看免费下载相关推荐SadTalker技术解析如何用单张图片和音频生成逼真3D面部动画SadTalker技术解析如何用单张图片和音频生成逼真3D面部动画 在数字内容创作领域音频驱动的人脸动画技术一直是计算机视觉和图形学的核心挑战。传统方法需要人工智能媒体生成计算机视觉深度学习数字人Geist字体现代开发者的终极开源字体解决方案Geist字体现代开发者的终极开源字体解决方案 在当今数字产品设计中字体选择直接影响用户体验和界面美感。Geist字体家族作为Vercel与Basement设计系统前端DOM 操作与事件处理完全指南用 JavaScript 动态操控网页DOM 操作与事件处理完全指南用 JavaScript 动态操控网页 导读 本文基于 foundations/javascript_basics/DOM_ma文档网络安全教程上一篇抖音批量下载工具 douyin-downloader 完整指南从配 Cookie 到整页作品入库下一篇Outfit 字体9 字重一次装齐可变字体零请求切粗细创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案