国庆节10月1日
--


事件是发生在元素上的"事情",事件监听就是提前安排"谁来管这件事"——用 addEventListener 绑定、记牢三要素,认识鼠标键盘焦点表单四类常见事件,最后把重复代码抽成函数放进 js 文件
.webp)
16 篇的 JS 是”页面一打开就执行”:颜色染好、文字换掉,然后就没它什么事了。可网页要动起来,得等用户做点什么——点一下按钮、鼠标划过去、敲键盘。这一篇讲的就是”用户做了事,JS 怎么知道、怎么做响应”,也就是事件监听。
PPT 用两个问句把概念引出来:
事件:HTML 事件是发生在 HTML 元素上的 “事情”。比如:
- 按钮被点击
- 鼠标移动到元素上
- 按下键盘按键
事件监听:JavaScript 可以在事件触发时,就立即调用一个函数做出响应,也称为 事件绑定 或 注册事件。
大白话拆一下:
| 说法 | 大白话 | 例子 |
|---|---|---|
| 事件 | “发生了什么” | 用户点了”删除”按钮 |
| 事件监听 | “提前安排好:这件事发生了就执行这段代码” | 点了删除按钮 → 就把那一行数据删掉 |
注意”提前安排”这四个字:JS 不是一直盯着用户看,而是把”套路”写下来交给浏览器;等事件真的发生了,浏览器回来调用我们写的那个函数。
语法只有一行:
1事件源.addEventListener('事件类型', 事件触发执行的函数);PPT 把这一行拆成三要素:
| 三要素 | 含义 | 落在代码的哪里 |
|---|---|---|
| 事件源 | 哪个 DOM 元素触发了事件(要先获取 DOM 元素) | addEventListener 前面的那部分 |
| 事件类型 | 用什么方式触发,比如鼠标单击 click | 第一个参数(字符串) |
| 事件触发执行的函数 | 要做什么事 | 第二个参数(回调函数) |
课程代码 08. JS-事件监听.html 的一个按钮,完整写出来就是:
1<input id="btn" type="button" value="点我一下试试2">2
3<script>4 // 事件源:document.querySelector('#btn')5 // 事件类型:'click'6 // 要做的事:弹一句"试试就试试"7 document.querySelector('#btn').addEventListener('click', () => {8 alert('试试就试试');9 });10</script>第二个参数只能写”函数”,不能写”函数的调用”——多一对括号,行为就完全变了:
1// ❌ 加了括号:sayHello() 是"立刻执行",把执行结果(undefined)当成了回调2// 结果:页面一加载就弹窗,点击按钮反而毫无反应3document.querySelector('#btn').addEventListener('click', sayHello());4
5// ✅ 只写函数名(或写完整的匿名函数):交给浏览器,等点击了再调用6document.querySelector('#btn').addEventListener('click', sayHello);7
8// ✅ 匿名函数/箭头函数也都是这个道理9document.querySelector('#btn').addEventListener('click', () => { sayHello(); });同样别忘的事件类型是字符串:'click' 有引号,写成 click 会被当成一个没定义的变量,监听直接失效。
on事件 会被覆盖#PPT 还给了一种老写法,并说明了它和 addEventListener 的区别:
早期版本写法(了解):事件源.on事件 = function() { … } 区别:on 方式会被覆盖,addEventListener 方式可以绑定多次,拥有更多特性,推荐使用。
课程代码把两种写法摆在一起做了对比实验:
1//事件监听 - addEventListener (可以多次绑定同一事件)2document.querySelector('#btn1').addEventListener('click', () => {3 console.log('试试就试试~~');4});5document.querySelector('#btn1').addEventListener('click', () => {6 console.log('试试就试试22~~');7});8
9//事件绑定-早期写法 - onclick (如果多次绑定同一事件, 覆盖) - 了解10document.querySelector('#btn2').onclick = () => {11 console.log('试试就试试~~');12};13document.querySelector('#btn2').onclick = () => {14 console.log('试试就试试22~~');15};两个按钮长得一模一样,点起来的结果完全不同:
| 写法 | 点一次按钮,控制台输出 |
|---|---|
btn1:addEventListener 绑了 两次 | 试试就试试~~ 和 试试就试试22~~(两次绑定都生效) |
btn2:onclick 绑了 两次 | 只有 试试就试试22~~(后一次把前一次覆盖了) |
为什么 onclick 会被覆盖?因为 事件源.onclick 本质上是给元素的一个属性赋值——属性只能有一个值,赋第二次就把第一次冲掉了。addEventListener 是往元素的”监听器列表”里追加,所以能叠加、还能用 removeEventListener 精确移除。新代码统一用 addEventListener,onclick 看得懂就行。
PPT 把常用事件分成四类(鼠标、键盘、焦点、表单),这张表要记个大概,写的时候按需查:
| 分类 | 事件 | 触发时机 | 常见用途 |
|---|---|---|---|
| 鼠标事件 | click | 鼠标点击 | 点按钮、点删除 |
mouseenter | 鼠标移入元素 | 划过去高亮某一行 | |
mouseleave | 鼠标移出元素 | 划走恢复原样 | |
| 键盘事件 | keydown | 键盘按下触发 | 回车提交、输入快捷键 |
keyup | 键盘抬起触发 | 统计按键 | |
| 焦点事件 | focus | 元素获得焦点 | 输入框被选中时给提示 |
blur | 元素失去焦点 | 离开输入框时做校验 | |
| 表单事件 | input | 用户输入时触发(每敲一个字都触发) | 实时字数统计、搜索联想 |
submit | 表单提交时触发 | 提交前做校验 |
课程代码 10. JS-常见事件.html 把九个事件全写了一遍(页面是一个小表单 + 一张成绩表),九段监听挨个对应上面这张表:
1<form action="" style="text-align: center;">2 <input type="text" name="username" id="username">3 <input type="text" name="age" id="age">4 <input id="b1" type="submit" value="提交">5 <input id="b2" type="button" value="单击事件">6</form>7
8<table width="800px" border="1" cellspacing="0" align="center">9 <tr>10 <th>学号</th><th>姓名</th><th>分数</th><th>评语</th>11 </tr>12 <tr align="center">13 <td>001</td><td>张三</td><td>90</td><td>很优秀</td>14 </tr>15 <tr align="center" id="last">16 <td>002</td><td>李四</td><td>92</td><td>优秀</td>17 </tr>18</table>19
20<script>21 //click: 鼠标点击事件22 document.querySelector('#b2').addEventListener('click', () => {23 console.log("我被点击了...");24 })25
26 //mouseenter: 鼠标移入27 document.querySelector('#last').addEventListener('mouseenter', () => {28 console.log("鼠标移入了...");29 })30
31 //mouseleave: 鼠标移出32 document.querySelector('#last').addEventListener('mouseleave', () => {33 console.log("鼠标移出了...");34 })35
36 //keydown: 某个键盘的键被按下37 document.querySelector('#username').addEventListener('keydown', () => {38 console.log("键盘被按下了...");39 })40
41 //keyup: 某个键盘的键被抬起42 document.querySelector('#username').addEventListener('keyup', () => {43 console.log("键盘被抬起了...");44 })45
46 //blur: 失去焦点事件47 document.querySelector('#age').addEventListener('blur', () => {48 console.log("失去焦点...");49 })50
51 //focus: 元素获得焦点52 document.querySelector('#age').addEventListener('focus', () => {53 console.log("获得焦点...");54 })55
56 //input: 用户输入时触发57 document.querySelector('#age').addEventListener('input', () => {58 console.log("用户输入时触发...");59 })60
61 //submit: 提交表单事件62 document.querySelector('form').addEventListener('submit', () => {63 alert("表单被提交了...");64 })65</script>用控制台(F12 → Console)能一个个验证出来,其中有两条容易踩的细节:
input 触发得非常勤:在年龄框里敲 123,控制台会响 3 次(每敲一个字符一次);keydown / keyup 也是每个键都触发。写 console.log 没关系,真做”实时校验”时要考虑性能。submit 有”默认行为”:表单提交后浏览器会带着参数刷新页面(课程的 action="" 就是提交到当前页)。所以点了”提交”你会看到 alert 之后页面一闪——后面学 Ajax 时,会用”阻止默认行为”把刷新掐掉,改成局部更新。回调函数里能做的事,就是 16 篇学的那些 DOM 操作,加上事件自己的”上下文”:
1// 1. 打印/弹窗:先看事件到底有没有触发(调试最常用)2document.querySelector('#btn').addEventListener('click', () => {3 console.log('我被点击了...');4});5
6// 2. 改当前元素自己的内容或样式7document.querySelector('#btn').addEventListener('click', function () {8 this.innerText = '已点击'; // this 就是"被点的那个按钮"9 this.style.backgroundColor = '#e6f7ff'; // 顺手换个背景色10});11
12// 3. 读输入框里的值,再做判断13document.querySelector('#age').addEventListener('blur', function () {14 if (this.value < 18) {15 alert('未成年不能报名');16 }17});两个要点:
this 就是”事件源”:回调写成 function(){} 时,函数里的 this 指向触发事件的那个元素——不用再 querySelector 一遍。但箭头函数没有自己的 this(15 篇在对象方法里讲过同一个坑),要用 this 就拿不到元素。想用 this 写 function(){},只是打印日志用箭头函数无所谓。addEventListener('click', (event) => { console.log(event.target); })——event.target 是真正被点到的那个元素(在”一整块区域里有很多小按钮”的场景里特别有用)。PPT 之外的这种参数后面做项目会经常见到,见一次认一次就行。PPT 第 35 页的案例:
需求:实现鼠标移入数据行时,背景色改为
#f2e2e2,鼠标移出时,再将背景色改为白色。
课程给的 AI 提示词(Prompt):
1通过js实现鼠标移入移出隔行换色效果,鼠标移入时,背景色为#f2e2e2;鼠标移出,背景色统一显示白色...
#f2e2e2),其他行还是原来的颜色;鼠标一移开,这一行就恢复课程代码 09. JS-案例-员工列表.html 的脚本(在 12 篇做好的表格基础上加):
1//通过JS为上述的表格中数据行添加事件监听, 实现鼠标进入后, 背景色#f2e2e2; 鼠标离开后, 背景色需要设置为#fff; (JS新版本的语法)2// 1. 获取所有的tr标签3let trs = document.querySelectorAll('tr');4
5// 2. 为每一个tr标签添加事件监听6for (let i = 0; i < trs.length; i++) {7 trs[i].addEventListener('mouseenter', function () { // mouseenter 鼠标进入8 trs[i].style.backgroundColor = '#f2e2e2';9 });10
11 trs[i].addEventListener('mouseleave', function () { // mouseleave 鼠标离开12 trs[i].style.backgroundColor = '#fff';13 })14}用三要素对照一下,套路和 16 篇的隔行换色一模一样,只是”每一步干什么”从改样式变成了绑监听:
| 三要素 | 这里是什么 |
|---|---|
| 事件源 | trs[i]——第 i 行(用循环给每一行都绑一份) |
| 事件类型 | 'mouseenter' 移入、'mouseleave' 移出(两个事件,绑两次) |
| 要做的事 | 把 this/这一行的背景色改成 #f2e2e2 或 #fff |
课程这段代码有两个”将就”的地方,抄的时候知道自己在将就:
querySelectorAll('tr') 把表头行 thead 里的 tr 也选进来了:鼠标划过表头时,表头那一行的 tr 背景确实也被改成了浅粉,只是表头的 th 自带背景色(#f2f2f2)把它盖住了,肉眼看不出来。要只作用于数据行,写成 document.querySelectorAll('tbody tr')。#fff:如果这页同时用了 16 篇的”隔行换色”,鼠标划一圈回来那一行的隔行色就没了(被白色覆盖)。想两全,就得在移出时按这一行原本的规律还原颜色——循环变量 i 还在作用域里,正好用得上:1trs[i].addEventListener('mouseenter', function () {2 this.style.backgroundColor = '#f2e2e2'; // 移入:先变浅粉3});4trs[i].addEventListener('mouseleave', function () {5 // 移出:按行号还原本来的隔行色(还是"奇数行/偶数行"那套判断)6 this.style.backgroundColor = (i % 2 == 0) ? '#f2e2e2' : '#e6f7ff';7});顺便说清一件事:“鼠标划过去变色”这种纯视觉效果,CSS 一行就能做——tbody tr:hover { background-color: #f2e2e2; }(:hover 就是”鼠标悬停”)。课程用 JS 来做,是为了练事件监听的写法。
判断标准:只是”看起来变了”→ CSS;需要”发生一件事”(点击后删除、输入后校验、提交后发请求)→ JS 事件。 后者 CSS 永远做不到。
PPT 在这之前先抛出两个问号:复用?? 维护??

10. JS-常见事件.html 里的脚本——九段监听,每一段开头都是 document.querySelector('#xxx').addEventListener(...),名字一模一样的重复代码连成一长串,而且全挤在 HTML 里这正是要被优化的地方。课程走了两步:
js/ 目录下的独立文件#HTML 里只留一行引入,剩下的都在外部文件里:
1<!-- type="module" 模块化JS -->2<script src="./js/eventDemo.js" type="module"></script>export / import)——重复的代码抽成”工具函数”#
xxxx.html 引入 js/eventDemo.js(type="module"),eventDemo.js 顶部又用 import 从 js/utils.js 拿工具函数;utils.js 里用 export 把 printLog(msg) 暴露出去——页面、业务代码、工具代码各占一个文件三个文件各管一段,代码长这样:
1// js/utils.js —— 工具函数:谁都能用的通用能力2export function printLog(msg){3 console.log(msg);4}1// js/eventDemo.js —— 业务代码:这个页面的事件都在这儿2import { printLog } from "./utils.js"; // 从工具文件里拿函数3
4//click: 鼠标点击事件5document.querySelector('#b2').addEventListener('click', () => {6 printLog("我被点击了...");7})8
9//mouseenter: 鼠标移入10document.querySelector('#last').addEventListener('mouseenter', () => {11 printLog("鼠标移入了...");12})13
14//mouseleave: 鼠标移出15document.querySelector('#last').addEventListener('mouseleave', () => {16 printLog("鼠标移出了...");17})1<!-- 11. JS-常见事件(优化).html —— 页面里只剩一行引入 -->2<script src="./js/eventDemo.js" type="module"></script>优化前后对比:
| 对比项 | 优化前(脚本写在 HTML 里) | 优化后(外部文件 + 模块化) |
|---|---|---|
| 复用 | 想重用只能复制粘贴 | printLog 在 utils.js 里导出一次,任何文件 import 就能用 |
| 维护 | 改一个公共逻辑要在九段代码里翻 | 改 utils.js 一处,所有调用它的地方一起变 |
| 页面文件 | HTML 里塞几百行 JS,结构和行为混在一起 | HTML 只管结构,js/ 目录管行为 |
模块化 JS 不能用 file:// 双击打开! 只要 <script> 上写了 type="module"、文件里用了 import,浏览器就会按”跨域”处理这个 JS 文件,双击打开的地址是 file:///...(源的 origin 是 null),会被直接拦下来,控制台报:
1Access to script at 'file:///..../js/eventDemo.js' from origin 'null' has been blocked by CORS policy页面看上去没报错,但事件一个都不响应。要用本地服务器访问——课程用的是 VS Code 插件 Live Server(地址栏是 http://127.0.0.1:5501/...,PPT 里那个案例截图就是它)。装好插件后右键 html 文件 → Open with Live Server 即可。
还没学服务器也不要紧:这一篇的练习都不用模块化,普通 <script> 内联或外链(不带 type="module")双击就能跑。
“抽函数”和”模块化”其实是两件事:
<script> 里就能做,这是”代码优化”的第一步;export / import 拆文件)——需要本地服务器环境,是把”复用”扩展到多个文件之间的工具;后面 Vue 项目的每个 .vue 文件、api/ 目录里的 export 都是它。顺序就是这个顺序:先抽函数,再考虑拆文件。
| 问题 | 答案 |
|---|---|
| 什么是事件? | HTML 事件是发生在 HTML 元素上的 “事情”——按钮被点击、鼠标移动到元素上、按下键盘按键 |
| 什么是事件监听? | JS 在事件触发时立即调用一个函数做出响应,也叫事件绑定或注册事件 |
| 事件监听的语法? | 事件源.addEventListener('事件类型', 事件触发执行的函数); |
| 三要素是什么? | 事件源(先获取 DOM 元素)、事件类型(如 'click')、事件触发执行的函数(要做什么事) |
| 早期写法和区别? | 事件源.on事件 = function(){}(了解)——on 方式会被覆盖,addEventListener 可以绑定多次,推荐使用 |
| 四类常见事件? | 鼠标:click / mouseenter / mouseleave;键盘:keydown / keyup;焦点:focus / blur;表单:input(每敲一个字符都触发)/ submit(提交,默认会刷新页面) |
| 回调函数里能做什么? | 用 16 篇的 DOM 操作——打印/弹窗、this.innerText、this.style.xxx、读 this.value;function(){} 里的 this 就是事件源,箭头函数没有自己的 this |
| 代码怎么优化? | ① 抽成函数(重复逻辑收进一处,无需额外环境)② 搬到 js/ 外部文件,用 <script src="./js/xxx.js"> 引入 ③ 跨文件复用用模块化:utils.js 里 export、业务文件里 import { printLog } from "./utils.js",引入的 <script> 要加 type="module" |
| 模块化有什么坑? | file:// 双击打开会被 CORS 策略拦截(控制台报 blocked by CORS policy),必须用本地服务器(如 VS Code 的 Live Server)访问 |
事件源.addEventListener('事件类型', 事件触发执行的函数);'click')、事件触发执行的函数(要做什么事)addEventListener('click', sayHello()) 会变成”页面一加载就执行”,点击反而没反应;事件类型是字符串,'click' 的引号不能少事件源.on事件 = function(){};区别是 on 方式会被覆盖(后一次赋值冲掉前一次),而 addEventListener 可以绑定多次,同一事件绑两遍两个都会执行——推荐用 addEventListenerclick(点击)/ mouseenter(移入)/ mouseleave(移出);键盘 keydown(按下)/ keyup(抬起);焦点 focus(获得焦点)/ blur(失去焦点);表单 input(用户输入时,每敲一个字符触发一次)/ submit(表单提交)submit 有默认行为——提交后浏览器会带着参数刷新页面;input 触发非常频繁,写实时逻辑时要注意console.log() / alert() 看效果、this.innerText 改内容、this.style.backgroundColor 改样式、this.value 读输入值function(){} 时 this 就是事件源(被点的那个元素);箭头函数没有自己的 this,要用 this 就别写箭头函数js/ 外部文件用 <script src="./js/xxx.js"> 引入;跨文件复用靠模块化——utils.js 里 export function printLog(msg){...}、业务文件里 import { printLog } from "./utils.js",引入的 <script> 必须加 type="module",而且不能用 file:// 双击打开(会被 CORS 拦截),要用本地服务器(Live Server) 2-1 给按钮绑定点击事件
页面上有一个按钮(id 为 btn)。要求:点击这个按钮时,弹出提示文字”试试就试试”(用浏览器弹窗,别只打印到控制台)。
(练习文件 test_17_点击事件.html 里已经准备好了按钮和写作区。)
一级 · 思路:先”抓住”按钮,再告诉它”被点击时干什么”——三要素一个个对上
二级 · 方法:document.querySelector('#btn').addEventListener('click', 函数);弹窗用 alert('...')
三级 · 骨架:document.querySelector('#btn').____________('click', () => { ____('试试就试试'); });
1document.querySelector('#btn').addEventListener('click', () => {2 alert('试试就试试');3});对照课程 08. JS-事件监听.html 和 PPT 第 33 页(那页的两种写法就是 addEventListener 和 onclick)。检查点:点一次按钮弹一次窗,页面上其他地方点击不该弹。
2-2 同一个按钮绑两次,再和 on 方式比一比
页面上有两个按钮:btn1 和 btn2。要求:
btn1 用监听方式绑定两次点击事件:第一次打印”试试就试试~~“、第二次打印”试试就试试22~~”btn2 用 on 方式也绑定两次点击事件:内容同上test_17_绑定方式对比.html 里已经准备好了两个按钮和写作区。)一级 · 思路:就是把课程 08. JS-事件监听.html 的对比实验自己写一遍
二级 · 方法:监听方式 addEventListener('click', ...) 可以写两遍;on 方式是 元素.onclick = 函数,赋值两次
三级 · 骨架:document.querySelector('#btn1').addEventListener('click', () => { console.log('____'); });(再来一次)/ document.querySelector('#btn2').onclick = () => { console.log('____'); };(再来一次)
1//1. addEventListener 绑两次:两次都会执行2document.querySelector('#btn1').addEventListener('click', () => {3 console.log('试试就试试~~');4});5document.querySelector('#btn1').addEventListener('click', () => {6 console.log('试试就试试22~~');7});8
9//2. on 方式绑两次:后一次覆盖前一次10document.querySelector('#btn2').onclick = () => {11 console.log('试试就试试~~');12};13document.querySelector('#btn2').onclick = () => {14 console.log('试试就试试22~~');15};结果:点 btn1 控制台出现两行,点 btn2 只出现一行(试试就试试22~~)。原因:onclick 是给元素的属性赋值,属性只有一个值;addEventListener 是往监听器列表里追加,能叠加。
2-3 鼠标移入移出换背景色
页面上有一张成绩表(表头 + 3 行数据)。要求:鼠标移入某一行时,这一行背景色变成 #f2e2e2;鼠标移出时,这一行恢复成白色。
(练习文件 test_17_鼠标移入移出.html 里已经准备好了表格和写作区。)
一级 · 思路:要给”每一行”都绑上监听(得用循环),而且是两个事件各绑一次
二级 · 方法:document.querySelectorAll('tbody tr') 拿到所有数据行;循环里 trs[i].addEventListener('mouseenter', 函数) 和 'mouseleave';改背景色用 style.backgroundColor
三级 · 骨架:let trs = document.querySelectorAll('____'); / for (let i = 0; i < trs.____; i++) { / trs[i].addEventListener('____', function () { trs[i].style.________ = '#f2e2e2'; }); / 再绑一个 '____' 设成 '#fff'
1// 1. 获取所有数据行(只拿 tbody 里的,表头不参与)2let trs = document.querySelectorAll('tbody tr');3
4// 2. 给每一行都绑上"移入/移出"两个监听5for (let i = 0; i < trs.length; i++) {6 trs[i].addEventListener('mouseenter', function () { // 鼠标移入7 trs[i].style.backgroundColor = '#f2e2e2';8 });9
10 trs[i].addEventListener('mouseleave', function () { // 鼠标移出11 trs[i].style.backgroundColor = '#fff';12 });13}对照课程 09. JS-案例-员工列表.html 的脚本(课程里写的是 querySelectorAll('tr'),会把表头也算进去;这里只选 tbody tr)。检查点:鼠标划过哪一行,就只有那一行变色。
2-4 让输入框”有反应”
页面上有一个姓名输入框(id 为 username)和一个显示区(id 为 tip)。要求:
test_17_焦点与输入事件.html 里已经准备好了输入框、显示区和写作区。)一级 · 思路:同一个输入框要绑三个事件,每个事件里都是”改另一个元素的文字”
二级 · 方法:事件类型 'focus'、'blur'、'input';读输入框内容用 this.value 或 输入框.value;改文字用 innerText(里面要拼变量就用模板字符串)
三级 · 骨架:let input = document.querySelector('#username'); / let tip = document.querySelector('#tip'); / input.addEventListener('____', function () { tip.innerText = '正在输入姓名…'; }); / input.addEventListener('blur', function () { tip.innerText = 输入完成:${this.____}; }); / input.addEventListener('____', function () { tip.innerText = this.value; });
1let input = document.querySelector('#username');2let tip = document.querySelector('#tip');3
4//1. 获得焦点5input.addEventListener('focus', function () {6 tip.innerText = '正在输入姓名…';7});8
9//2. 失去焦点:拼上当前输入的内容10input.addEventListener('blur', function () {11 tip.innerText = `输入完成:${this.value}`;12});13
14//3. 输入时实时回显15input.addEventListener('input', function () {16 tip.innerText = this.value;17});对照课程 10. JS-常见事件.html 里 focus / blur / input 三段。三个检查点:① 光标点进输入框 → 提示变”正在输入姓名…”;② 敲字时显示区跟着变;③ 点到别处 → 变成”输入完成:xxx”。注意 this.value 读的是输入框里的内容(不是 innerHTML)。
3-1 做一个”个人名片”小交互页
页面上有一张名片(#card)、一个”换个问候语”按钮(#greetBtn)、一个昵称输入框(#nickname)和一行状态提示(#status)。要求做出三个交互,并把重复的逻辑抽成函数:
#greeting)改成”你好,欢迎来看我的主页”(连点多次效果相同即可)#e6f7ff,移出恢复白色setStatus(text)),第 3 步的三个事件里都调用它,而不是各写一遍
(练习文件 test_17_综合_交互三连.html 里已经准备好了页面元素和写作区。)
(进阶·可选:把 setStatus 挪到 js/utils.js 用 export/import 引入——这一步需要用 Live Server 打开,双击是跑不起来的。)一级 · 思路:三个交互分别对应三组事件;第 4 步是”代码优化”里的第一步——抽函数,函数不需要任何额外环境,普通 <script> 就行
二级 · 方法:点击 'click'、移入移出 'mouseenter'/'mouseleave'、输入 'input'、失焦 'blur';改文字 innerText;函数定义 function setStatus(text){ ... },调用 setStatus('...')
三级 · 骨架:function setStatus(text) { document.querySelector('#status').____ = text; } / document.querySelector('#greetBtn').addEventListener('____', () => { document.querySelector('#greeting').innerHTML = '____'; }); / card.addEventListener('mouseenter', () => { card.style.________ = '#e6f7ff'; }); / input.addEventListener('input', () => { setStatus(当前昵称:${input.____}); });
1// 先定义"改状态提示"的工具函数:重复逻辑只写一次2function setStatus(text) {3 document.querySelector('#status').innerText = text;4}5
6let card = document.querySelector('#card');7let nickname = document.querySelector('#nickname');8
9//1. 点击按钮改问候语10document.querySelector('#greetBtn').addEventListener('click', () => {11 document.querySelector('#greeting').innerHTML = '你好,欢迎来看我的主页';12});13
14//2. 鼠标移入移出换背景色15card.addEventListener('mouseenter', () => {16 card.style.backgroundColor = '#e6f7ff';17});18card.addEventListener('mouseleave', () => {19 card.style.backgroundColor = '#fff';20});21
22//3. 输入实时回显 + 失焦确认(三处都调用工具函数)23nickname.addEventListener('input', () => {24 setStatus(`当前昵称:${nickname.value}`);25});26nickname.addEventListener('focus', () => {27 setStatus('正在输入昵称…');28});29nickname.addEventListener('blur', () => {30 setStatus('昵称已确定');31});三个检查点:① 点按钮后名片上的问候语变了;② 鼠标划进名片变浅蓝、划出变白;③ 输入框每敲一个字状态行都跟着变,三处提示都走 setStatus 这一个函数(想改提示的样式,只改函数里那一行就够了——这就是”抽函数”带来的好处)。
进阶版验证方式:把 setStatus 移到 js/utils.js 里写成 export function setStatus(text) {...},主文件顶部 import { setStatus } from "./utils.js";,<script> 加 type="module",然后用 Live Server 打开——直接双击(file://)会报 CORS,事件全都不响应。
如果你喜欢,那么欢迎来到我的世界!
了解更多暂未播放



"所有的相遇都是久别重逢。"—— 未知


