← FC Coder · HomePhase 02 · Lesson 18 · 60 min
Lesson18
Phase Two · Fantasy Builder · Matchday 18 · The Bell

事件 + 点击
onClick

Today's 3 Jobs · 今天这三件事
  1. 01
    PlayerCard 加 onClick={() => alert(...)}
    必须包箭头函数
  2. 02
    加 <button> 加入阵容 · 点弹 alert
    比 article 更 semantic
  3. 03
    感受 · 主动 → 被动心智反转
    Phase 2 第 2 个本质点

上节课卡显示完美 · 但没反应。今天 onClick 进场 —— 你点 · 卡反应。Phase 2 第 2 个本质点 · 事件驱动。从「主动跑代码」翻到「等用户点」—— 心智彻底反转。这是所有真应用的形状。

Essence · 本质点

事件驱动 · 不是你问 · 是用户告诉浏览器

按铃叫服务员 · 没按服务员不动。事件 = 用户的「按铃」。

Chalk Board · 心智反转
<button onClick={() => alert('Hi')} >
点我
</button>
Phase 0-17
主动 · 你写代码立刻跑
今天起
被动 · 等用户点才跑
真应用
永远是事件驱动

onClick={() => action()} 是「注册一个回调 —— 当被点时跑」。函数本身不立刻跑 · 只在事件触发时被调。

Essence · 包 vs 不包

onClick 里必须放函数 · 不是函数调用结果

onClick={alert()} ❌ · onClick={() => alert()} ✅

Chalk Board · 两种写法
不包箭头 · alert 立刻跑 · onClick 收到 undefined
包箭头 · 造一个函数 · 用户点才跑
❌ 立刻跑
onClick={alert('Hi')}
✅ 等点才跑
onClick={() => alert('Hi')}
记法
有 () => 才是函数
Roster · 今天 3 个新工具

onClick · button · 回调里用 props

抄着用 · 看卡能反应是今天的「哇」。

  1. 01
    onClick={() => action()}
    按铃 —— 用户点这个 · 跑这个函数。
    必须包箭头函数。onClick={action()} 立刻跑 · 不等点。
  2. 02
    <button onClick={...}>
    Semantic 按钮 —— 自动支持键盘触发 + 读屏软件认。
    比 article onClick 好。Tab 聚焦 + 空格触发免费。
  3. 03
    () => alert(`选了 ${player.name}`)
    回调里用 props —— 函数体里能访问 player.name。
    22 张卡共享一个 onClick 写法 · 每张 player.name 自动正确。
Half 2 · 在屏幕上

让卡能反应 · 第一次事件驱动

做完一步就点 ✓。Step 2 那一下点卡弹 alert · 心智反转完成。

01第一个 onClick · article
01Min

Cursor + pnpm dev

打开 components/player-card/index.tsx。
02Min

<article> 加 onClick={() => alert(`你选了 ${player.name}!`)}

在 className 旁边加 onClick。保存 · sandbox 点哈兰德卡 · 弹「你选了 哈兰德!」🔔
03Min

点不同卡看不同 alert

点福登 → 你选了 福登!点罗德里 → 你选了 罗德里!22 张共享一个写法 · player.name 自动正确。
04Min

改 alert → console.log 看 DevTools Console

alert 拦截用户 · console.log 静默记录。实际程序用 console 多。改一下 · 点卡 · 看 Console 出现一行。
02升级到 <button> + 加入阵容
05Min

<article> 里加 <button onClick={...}>加入阵容</button>

<button onClick={() => alert(`${player.name} 加入阵容!`)} className="mt-2 rounded bg-amber-500 px-3 py-1 text-slate-900">加入阵容</button>。每张卡有按钮。
06Min

去掉 article 的 onClick · 只留 button

点 button 又冒泡到 article 弹两次 —— 砍 article onClick。专一 button 触发。今天不讲 stopPropagation(Phase 3)。
07Min

Tab 键聚焦 · 空格 / 回车触发

用 Tab 键移到按钮 · 空格 / 回车也弹 alert。<button> 自动支持键盘 —— <article onClick> 不支持。Semantic 在事件层的好处。
03多个 button · 各自函数
08Min

加第二个按钮 · 状态查询

<button onClick={() => alert(`${player.name} 状态查询`)}>状态</button>。放加入阵容旁边。两个按钮各自函数。
04玩 · 截图
09Min

试 onMouseOver={() => console.log(player.name)}

鼠标停在卡上自动 log · 不点击。事件还有 onMouseMove / onKeyDown / onScroll 等等 100+ · 今天只 onClick + 顺嘴试一个 onMouseOver。
10Min

📸 截图

存 2026-XX-XX-我的卡能反应.png · Phase 2 第三张战利品。
Half Time · 中场 · 讲给爸爸听

4 题 · 重点:事件驱动 · 主动 vs 被动

第 2 题让他用「包 vs 不包」的画面讲。

01什么是事件驱动?用「按铃叫服务员」的比喻讲。Hint ↓

用户主动触发 · 你不主动跑 · 等用户告诉浏览器做什么。Phase 0-17 主动 · 今天起被动。

02onClick={() => alert()} 和 onClick={alert()} 差在哪?Hint ↓

前者包箭头函数 · 等点才跑;后者立刻跑 alert · onClick 收到 undefined。

03为什么 <button> 比 <article onClick> 好?Hint ↓

Semantic + 键盘可触发 + 读屏软件认。Phase 1 #07 Semantic 在事件层的延伸。

04今天主动还是被动心智?哪种更接近真应用?Hint ↓

被动 —— 真应用永远等用户 · 用户没动就没事干。Phase 0 主动是为了破冰 · 真世界是事件驱动的。

Player Rating · 本课温度计

给「卡能反应」打个分

说真话。爸爸会看到。

今天难度Difficulty
0
今天开心Fun
0
Final Whistle · 终场哨

你的卡能反应了 —— 事件驱动登场。

还有 10 步没打勾。Step 2 第一次点卡弹 alert 那一下今天就过 —— 其他下次补。