第 148 章:事件处理
学习目标
- 掌握 React 事件系统(onClick 等)
- 理解事件对象与类型化
- 学会事件传参
- 处理表单事件和键盘事件
一、React 事件基础
1.1 命名约定
tsx
// HTML:小写
<button onclick="handleClick()">
// React:camelCase
<button onClick={handleClick}>1.2 常见事件
| 鼠标 | 键盘 | 表单 | 焦点 |
|---|---|---|---|
onClick | onKeyDown | onChange | onFocus |
onDoubleClick | onKeyUp | onInput | onBlur |
onMouseEnter | onKeyPress | onSubmit | onFocusCapture |
onMouseLeave | onReset | ||
onContextMenu |
二、事件处理器
2.1 直接定义
tsx
function Button() {
return <button onClick={() => console.log('clicked')}>点我</button>;
}2.2 提取函数
tsx
function Button() {
function handleClick() {
console.log('clicked');
}
return <button onClick={handleClick}>点我</button>;
}2.3 类型化事件
tsx
import { MouseEvent, ChangeEvent, FormEvent } from 'react';
function Form() {
function handleClick(e: MouseEvent<HTMLButtonElement>) {
console.log(e.currentTarget.disabled);
}
function handleChange(e: ChangeEvent<HTMLInputElement>) {
console.log(e.target.value);
}
function handleSubmit(e: FormEvent<HTMLFormElement>) {
e.preventDefault(); // 阻止默认提交
// ...
}
return (
<form onSubmit={handleSubmit}>
<input onChange={handleChange} />
<button onClick={handleClick}>提交</button>
</form>
);
}三、传参
3.1 用箭头函数
tsx
function List() {
function handleDelete(id: number) {
console.log('删除', id);
}
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
<button onClick={() => handleDelete(item.id)}>删除</button>
</li>
))}
</ul>
);
}3.2 用 data 属性
tsx
function List() {
function handleClick(e: MouseEvent<HTMLButtonElement>) {
const id = e.currentTarget.dataset.id;
console.log('删除', id);
}
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
<button data-id={item.id} onClick={handleClick}>删除</button>
</li>
))}
</ul>
);
}四、阻止默认与冒泡
4.1 preventDefault
tsx
function Link() {
function handleClick(e: MouseEvent) {
e.preventDefault(); // 不跳转
console.log('拦截了');
}
return <a href="/x" onClick={handleClick}>点我</a>;
}4.2 stopPropagation
tsx
function Card() {
function handleCardClick() {
console.log('card clicked');
}
function handleButtonClick(e: MouseEvent) {
e.stopPropagation(); // 阻止冒泡到 Card
console.log('button clicked');
}
return (
<div onClick={handleCardClick}>
<button onClick={handleButtonClick}>点我</button>
</div>
);
}五、表单处理
5.1 受控组件
tsx
function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
function handleSubmit(e: FormEvent) {
e.preventDefault();
console.log({ email, password });
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={e => setEmail(e.target.value)}
/>
<input
type="password"
value={password}
onChange={e => setPassword(e.target.value)}
/>
<button type="submit">登录</button>
</form>
);
}5.2 多个 input
tsx
function Form() {
const [form, setForm] = useState({ name: '', email: '' });
function update(field: keyof typeof form, value: string) {
setForm(f => ({ ...f, [field]: value }));
}
return (
<form>
<input
value={form.name}
onChange={e => update('name', e.target.value)}
/>
<input
value={form.email}
onChange={e => update('email', e.target.value)}
/>
</form>
);
}六、键盘事件
tsx
function Search() {
function handleKeyDown(e: KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') {
console.log('搜索', e.currentTarget.value);
}
if (e.key === 'Escape') {
e.currentTarget.blur();
}
}
return <input onKeyDown={handleKeyDown} />;
}七、本章小结
| 概念 | 关键 |
|---|---|
| 事件命名 | camelCase:onClick |
| 事件对象 | 类型化:MouseEvent<HTMLButtonElement> |
| 传参 | 箭头函数或 dataset |
| 阻止默认 | e.preventDefault() |
| 阻止冒泡 | e.stopPropagation() |
| 受控表单 | value + onChange |
动手练习
- 写一个登录表单,提交时打印表单数据
- 写一个搜索框,回车触发搜索,Esc 清空
- 写一个 Todo 列表,每项有删除按钮
- 写一个 Modal,点遮罩关闭,点内容不关闭