Skip to content
第 148 / 250 章前端⏱ 10 分钟阅读

第 148 章:事件处理

学习目标

  • 掌握 React 事件系统(onClick 等)
  • 理解事件对象与类型化
  • 学会事件传参
  • 处理表单事件和键盘事件

一、React 事件基础

1.1 命名约定

tsx
// HTML:小写
<button onclick="handleClick()">

// React:camelCase
<button onClick={handleClick}>

1.2 常见事件

鼠标键盘表单焦点
onClickonKeyDownonChangeonFocus
onDoubleClickonKeyUponInputonBlur
onMouseEnteronKeyPressonSubmitonFocusCapture
onMouseLeaveonReset
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

动手练习

  1. 写一个登录表单,提交时打印表单数据
  2. 写一个搜索框,回车触发搜索,Esc 清空
  3. 写一个 Todo 列表,每项有删除按钮
  4. 写一个 Modal,点遮罩关闭,点内容不关闭

推荐阅读


下一章:第 149 章:Hooks 之 useEffect

本站基于 VitePress 构建 · 由 Codebook 团队维护