常见组件(例如 <div>)

所有内置浏览器组件,例如 <div>,都支持一些通用的属性和事件。


参考

常见组件(例如 <div>

<div className="wrapper">一些内容</div>

查看更多示例。

属性

所有内置组件都支持这些特殊的 React 属性:

  • children:一个 React 节点(一个元素、字符串、数字、portal,一个空节点如 nullundefined 和布尔值,或其他 React 节点的数组)。指定组件内部的内容。当你使用 JSX 时,通常会通过嵌套标签(如 <div><span /></div>)隐式指定 children 属性。

  • dangerouslySetInnerHTML:一个形如 { __html: '<p>some html</p>' } 的对象,内部包含原始 HTML 字符串。它会覆盖 DOM 节点的 innerHTML 属性,并在其中显示传入的 HTML。应极其谨慎地使用!如果其中的 HTML 不可信(例如基于用户数据),就有引入 XSS 漏洞的风险。阅读更多关于使用 dangerouslySetInnerHTML 的内容。

  • ref:来自 useRefcreateRef 的 ref 对象,或一个 ref 回调函数,或用于 旧版 refs 的字符串。你的 ref 将填充为该节点的 DOM 元素。阅读更多关于使用 refs 操作 DOM 的内容。

  • suppressContentEditableWarning:一个布尔值。如果为 true,则会抑制 React 在元素同时具有 childrencontentEditable={true} 时显示的警告(这两者通常不能一起工作)。当你构建一个手动管理 contentEditable 内容的文本输入库时可使用此项。

  • suppressHydrationWarning:一个布尔值。如果你使用 服务端渲染,通常当服务端和客户端渲染出不同内容时会出现警告。在某些罕见情况下(如时间戳),要保证完全一致非常困难甚至不可能。如果将 suppressHydrationWarning 设为 true,React 将不会就该元素的属性和内容不匹配发出警告。它只作用于一层深度,并且 предназначляется 作为一种逃生出口。不要过度使用它。阅读关于抑制 hydration 错误的内容。

  • style:一个包含 CSS 样式的对象,例如 { fontWeight: 'bold', margin: 20 }。类似于 DOM 的 style 属性,CSS 属性名需要写成 camelCase,例如用 fontWeight 而不是 font-weight。你可以传入字符串或数字作为值。如果传入数字,例如 width: 100,React 会自动在值后追加 px(“像素”),除非它是一个 无单位属性。我们建议仅在你事先不知道样式值的动态样式中使用 style。在其他情况下,使用 className 应用普通 CSS 类会更高效。阅读更多关于 classNamestyle 的内容。

所有这些标准 DOM 属性也都支持用于所有内置组件:

你也可以将自定义属性作为 props 传入,例如 mycustomprop="someValue"。这在与第三方库集成时很有用。自定义属性名必须是小写且不能以 on 开头。其值会被转换为字符串。如果传入 nullundefined,自定义属性会被移除。

这些事件只会在 <form> 元素上触发:

这些事件只会在 <dialog> 元素上触发。与浏览器事件不同,它们在 React 中会冒泡:

这些事件只会在 <details> 元素上触发。与浏览器事件不同,它们在 React 中会冒泡:

这些事件会在 <img><iframe><object><embed><link>SVG <image> 元素上触发。与浏览器事件不同,它们在 React 中会冒泡:

这些事件会在诸如 <audio><video> 等资源上触发。与浏览器事件不同,它们在 React 中会冒泡:

注意事项

  • 你不能同时传入 childrendangerouslySetInnerHTML
  • 某些事件(如 onAbortonLoad)在浏览器中不会冒泡,但在 React 中会冒泡。

ref 回调函数

你可以向 ref 属性传入一个函数,而不是 ref 对象(例如 useRef 返回的那个)。

<div ref={(node) => {
console.log('Attached', node);

return () => {
console.log('Clean up', node)
}
}}>

查看一个使用 ref 回调的示例。

<div> DOM 节点被添加到屏幕上时,React 会用 DOM node 作为参数调用你的 ref 回调。当该 <div> DOM 节点被移除时,React 会调用回调返回的清理函数。

只要你传入的是一个不同的 ref 回调,React 也会调用你的 ref 回调。在上面的示例中,(node) => { ... } 在每次渲染时都是不同的函数。当你的组件重新渲染时,之前的函数会以 null 作为参数被调用,而下一个函数会以 DOM 节点作为参数被调用。

参数

  • node:一个 DOM 节点。当 ref 绑定时,React 会将 DOM 节点传给你。除非你在每次渲染时都为 ref 回调传入相同的函数引用,否则该回调会在组件的每次重新渲染期间临时执行清理并重新创建。

Note

React 19 为 ref 回调添加了清理函数。

为兼容旧版本,如果 ref 回调没有返回清理函数,那么当 ref 被解绑时,node 会以 null 被调用。此行为将在未来版本中移除。

返回值

  • 可选 cleanup function:当 ref 被解绑时,React 会调用清理函数。如果 ref 回调没有返回函数,那么当 ref 被解绑时,React 会再次以 null 作为参数调用该回调。此行为将在未来版本中移除。

注意事项

  • 当启用 Strict Mode 时,React 会在第一次真实的 setup 之前,额外执行一次仅开发环境可见的 setup+cleanup 循环。这是一个压力测试,用于确保你的清理逻辑能“镜像”你的 setup 逻辑,并停止或撤销 setup 所做的一切。如果这造成问题,请实现清理函数。
  • 当你传入一个不同的 ref 回调时,如果提供了清理函数,React 会调用之前回调的清理函数。如果没有定义清理函数,ref 回调将以 null 作为参数被调用。下一个函数将以 DOM 节点作为参数被调用。

React 事件对象

你的事件处理函数将接收一个 React 事件对象。它有时也被称为“合成事件”。

<button onClick={e => {
console.log(e); // React 事件对象
}} />

它遵循底层 DOM 事件相同的标准,但修复了一些浏览器不一致问题。

某些 React 事件不会直接映射到浏览器的原生事件。例如在 onMouseLeave 中,e.nativeEvent 会指向一个 mouseout 事件。具体映射并不是公共 API 的一部分,未来可能会改变。如果你出于某些原因需要底层浏览器事件,请从 e.nativeEvent 读取。

属性

React 事件对象实现了部分标准 Event 属性:

  • bubbles:一个布尔值。返回事件是否会通过 DOM 冒泡。
  • cancelable:一个布尔值。返回事件是否可被取消。
  • currentTarget:一个 DOM 节点。返回当前处理函数在 React 树中所附着的节点。
  • defaultPrevented:一个布尔值。返回是否调用了 preventDefault
  • eventPhase:一个数字。返回事件当前所处的阶段。
  • isTrusted:一个布尔值。返回事件是否由用户发起。
  • target:一个 DOM 节点。返回事件发生的节点(也可能是较远的子节点)。
  • timeStamp:一个数字。返回事件发生的时间。

此外,React 事件对象还提供这些属性:

  • nativeEvent:一个 DOM Event。原始浏览器事件对象。

方法

React 事件对象实现了部分标准 Event 方法:

此外,React 事件对象还提供这些方法:

  • isDefaultPrevented():返回一个布尔值,表示是否调用了 preventDefault
  • isPropagationStopped():返回一个布尔值,表示是否调用了 stopPropagation
  • persist():不用于 React DOM。对于 React Native,可调用它以在事件之后读取事件属性。
  • isPersistent():不用于 React DOM。对于 React Native,返回是否已调用 persist

注意事项

  • currentTargeteventPhasetargettype 的值反映的是你的 React 代码所期望的值。在底层,React 会在根节点附加事件处理函数,但这不会反映在 React 事件对象中。例如,e.currentTarget 可能与底层的 e.nativeEvent.currentTarget 不同。对于被 polyfill 的事件,e.type(React 事件类型)可能与 e.nativeEvent.type(底层类型)不同。

AnimationEvent 处理函数

用于 CSS 动画 事件的事件处理函数类型。

<div
onAnimationStart={e => console.log('onAnimationStart')}
onAnimationIteration={e => console.log('onAnimationIteration')}
onAnimationEnd={e => console.log('onAnimationEnd')}
/>

参数


ClipboardEvent 处理函数

用于 Clipboard API 事件的事件处理函数类型。

<input
onCopy={e => console.log('onCopy')}
onCut={e => console.log('onCut')}
onPaste={e => console.log('onPaste')}
/>

参数


CompositionEvent 处理函数

用于 输入法编辑器(IME) 事件的事件处理函数类型。

<input
onCompositionStart={e => console.log('onCompositionStart')}
onCompositionUpdate={e => console.log('onCompositionUpdate')}
onCompositionEnd={e => console.log('onCompositionEnd')}
/>

参数


DragEvent 处理函数

用于 HTML 拖放 API 事件的事件处理函数类型。

<>
<div
draggable={true}
onDragStart={e => console.log('onDragStart')}
onDragEnd={e => console.log('onDragEnd')}
>
拖拽源
</div>

<div
onDragEnter={e => console.log('onDragEnter')}
onDragLeave={e => console.log('onDragLeave')}
onDragOver={e => { e.preventDefault(); console.log('onDragOver'); }}
onDrop={e => console.log('onDrop')}
>
放置目标
</div>
</>

参数


FocusEvent 处理函数

用于焦点事件的事件处理函数类型。

<input
onFocus={e => console.log('onFocus')}
onBlur={e => console.log('onBlur')}
/>

查看一个示例。

参数


Event 处理函数

一种用于通用事件的事件处理函数类型。

参数


InputEvent 处理函数

一种用于 onBeforeInput 事件的事件处理函数类型。

<input onBeforeInput={e => console.log('onBeforeInput')} />

参数


KeyboardEvent 处理函数

一种用于键盘事件的事件处理函数类型。

<input
onKeyDown={e => console.log('onKeyDown')}
onKeyUp={e => console.log('onKeyUp')}
/>

查看示例。

参数


MouseEvent 处理函数

一种用于鼠标事件的事件处理函数类型。

<div
onClick={e => console.log('onClick')}
onMouseEnter={e => console.log('onMouseEnter')}
onMouseOver={e => console.log('onMouseOver')}
onMouseDown={e => console.log('onMouseDown')}
onMouseUp={e => console.log('onMouseUp')}
onMouseLeave={e => console.log('onMouseLeave')}
/>

查看示例。

参数


PointerEvent 处理函数

一种用于 指针事件 的事件处理函数类型。

<div
onPointerEnter={e => console.log('onPointerEnter')}
onPointerMove={e => console.log('onPointerMove')}
onPointerDown={e => console.log('onPointerDown')}
onPointerUp={e => console.log('onPointerUp')}
onPointerLeave={e => console.log('onPointerLeave')}
/>

查看示例。

参数


TouchEvent 处理函数

一种用于 触摸事件 的事件处理函数类型。

<div
onTouchStart={e => console.log('onTouchStart')}
onTouchMove={e => console.log('onTouchMove')}
onTouchEnd={e => console.log('onTouchEnd')}
onTouchCancel={e => console.log('onTouchCancel')}
/>

参数


TransitionEvent 处理函数

一种用于 CSS 过渡事件的事件处理函数类型。

<div
onTransitionEnd={e => console.log('onTransitionEnd')}
/>

参数


UIEvent 处理函数

一种用于通用 UI 事件的事件处理函数类型。

<div
onScroll={e => console.log('onScroll')}
/>

参数


WheelEvent 处理函数

一种用于 onWheel 事件的事件处理函数类型。

<div
onWheel={e => console.log('onWheel')}
/>

参数


用法

应用 CSS 样式

在 React 中,你可以使用 className. 指定一个 CSS 类。它的工作方式与 HTML 中的 class 属性类似:

<img className="avatar" />

然后你在单独的 CSS 文件中为它编写 CSS 规则:

/* 在你的 CSS 中 */
.avatar {
border-radius: 50%;
}

React 并不规定你如何添加 CSS 文件。在最简单的情况下,你需要向 HTML 添加一个 <link> 标签。如果你使用构建工具或框架,请查阅其文档,了解如何将 CSS 文件添加到你的项目中。

有时,样式值依赖于数据。使用 style 属性来动态传入一些样式:

<img
className="avatar"
style={{
width: user.imageSize,
height: user.imageSize
}}
/>

在上面的示例中,style={{}} 不是一种特殊语法,而是 style={ } JSX 花括号。 中的一个普通 {} 对象。我们建议只有在样式依赖于 JavaScript 变量时才使用 style 属性。

export default function Avatar({ user }) {
  return (
    <img
      src={user.imageUrl}
      alt={'照片:' + user.name}
      className="avatar"
      style={{
        width: user.imageSize,
        height: user.imageSize
      }}
    />
  );
}

Deep Dive

如何有条件地应用多个 CSS 类?

要有条件地应用 CSS 类,你需要自己使用 JavaScript 生成 className 字符串。

例如,className={'row ' + (isSelected ? 'selected': '')} 会根据 isSelected 是否为 true,生成 className="row"className="row selected"

为了让它更易读,你可以使用一个轻量的辅助库,比如 classnames:

import cn from 'classnames';

function Row({ isSelected }) {
return (
<div className={cn('row', isSelected && 'selected')}>
...
</div>
);
}

如果你有多个条件类,这会特别方便:

import cn from 'classnames';

function Row({ isSelected, size }) {
return (
<div className={cn('row', {
selected: isSelected,
large: size === 'large',
small: size === 'small',
})}>
...
</div>
);
}

使用 ref 操作 DOM 节点

有时,你需要获取与 JSX 中某个标签关联的浏览器 DOM 节点。例如,如果你想在按钮被点击时聚焦一个 <input>,你需要在浏览器的 <input> DOM 节点上调用 focus()

要获取某个标签对应的浏览器 DOM 节点,声明一个 ref 并将其作为 ref 属性传给该标签:

import { useRef } from 'react';

export default function Form() {
const inputRef = useRef(null);
// ...
return (
<input ref={inputRef} />
// ...

在渲染到屏幕后,React 会把 DOM 节点放入 inputRef.current 中。

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        聚焦输入框
      </button>
    </>
  );
}

进一步了解 使用 refs 操作 DOM查看更多示例。

对于更高级的用例,ref 属性也接受一个 回调函数。


危险地设置 inner HTML

你可以像这样向元素传递一段原始 HTML 字符串:

const markup = { __html: '<p>一些原始 html</p>' };
return <div dangerouslySetInnerHTML={markup} />;

这是危险的。与底层 DOM 的 innerHTML 属性一样,你必须格外小心!除非这段标记来自完全可信的来源,否则很容易通过这种方式引入 XSS 漏洞。

例如,如果你使用一个将 Markdown 转换为 HTML 的 Markdown 库,你信任它的解析器没有 bug,并且用户只会看到自己的输入,那么你可以像这样显示生成的 HTML:

import { Remarkable } from 'remarkable';

const md = new Remarkable();

function renderMarkdownToHTML(markdown) {
  // 这只有在安全时才成立,因为输出的 HTML
  // 会展示给同一个用户,而且你
  // 信任这个 Markdown 解析器没有 bug。
  const renderedHTML = md.render(markdown);
  return {__html: renderedHTML};
}

export default function MarkdownPreview({ markdown }) {
  const markup = renderMarkdownToHTML(markdown);
  return <div dangerouslySetInnerHTML={markup} />;
}

{__html} 对象应尽可能在生成 HTML 的位置附近创建,就像上面的示例在 renderMarkdownToHTML 函数中所做的那样。这样可以确保代码中使用的所有原始 HTML 都被明确标记,同时也确保只有你期望包含 HTML 的变量会传给 dangerouslySetInnerHTML。不建议像 <div dangerouslySetInnerHTML={{__html: markup}} /> 这样内联创建该对象。

要了解为什么渲染任意 HTML 是危险的,请将上面的代码替换为以下内容:

const post = {
// 想象一下,这段内容存储在数据库中。
content: `<img src="" onerror='alert("you were hacked")'>`
};

export default function MarkdownPreview() {
// 🔴 安全漏洞:将不受信任的输入传递给 dangerouslySetInnerHTML
const markup = { __html: post.content };
return <div dangerouslySetInnerHTML={markup} />;
}

嵌入在 HTML 中的代码会运行。黑客可以利用这个安全漏洞窃取用户信息,或者代表他们执行操作。只应将 dangerouslySetInnerHTML 用于可信且经过清理的数据。


处理鼠标事件

此示例展示了一些常见的 鼠标事件 以及它们何时触发。

export default function MouseExample() {
  return (
    <div
      onMouseEnter={e => console.log('onMouseEnter (parent)')}
      onMouseLeave={e => console.log('onMouseLeave (parent)')}
    >
      <button
        onClick={e => console.log('onClick (first button)')}
        onMouseDown={e => console.log('onMouseDown (first button)')}
        onMouseEnter={e => console.log('onMouseEnter (first button)')}
        onMouseLeave={e => console.log('onMouseLeave (first button)')}
        onMouseOver={e => console.log('onMouseOver (first button)')}
        onMouseUp={e => console.log('onMouseUp (first button)')}
      >
        第一个按钮
      </button>
      <button
        onClick={e => console.log('onClick (second button)')}
        onMouseDown={e => console.log('onMouseDown (second button)')}
        onMouseEnter={e => console.log('onMouseEnter (second button)')}
        onMouseLeave={e => console.log('onMouseLeave (second button)')}
        onMouseOver={e => console.log('onMouseOver (second button)')}
        onMouseUp={e => console.log('onMouseUp (second button)')}
      >
        第二个按钮
      </button>
    </div>
  );
}


处理指针事件

此示例展示了一些常见的 指针事件 以及它们何时触发。

export default function PointerExample() {
  return (
    <div
      onPointerEnter={e => console.log('onPointerEnter (parent)')}
      onPointerLeave={e => console.log('onPointerLeave (parent)')}
      style={{ padding: 20, backgroundColor: '#ddd' }}
    >
      <div
        onPointerDown={e => console.log('onPointerDown (first child)')}
        onPointerEnter={e => console.log('onPointerEnter (first child)')}
        onPointerLeave={e => console.log('onPointerLeave (first child)')}
        onPointerMove={e => console.log('onPointerMove (first child)')}
        onPointerUp={e => console.log('onPointerUp (first child)')}
        style={{ padding: 20, backgroundColor: 'lightyellow' }}
      >
        第一个子元素
      </div>
      <div
        onPointerDown={e => console.log('onPointerDown (second child)')}
        onPointerEnter={e => console.log('onPointerEnter (second child)')}
        onPointerLeave={e => console.log('onPointerLeave (second child)')}
        onPointerMove={e => console.log('onPointerMove (second child)')}
        onPointerUp={e => console.log('onPointerUp (second child)')}
        style={{ padding: 20, backgroundColor: 'lightblue' }}
      >
        第二个子元素
      </div>
    </div>
  );
}


处理焦点事件

在 React 中,焦点事件 会冒泡。你可以使用 currentTargetrelatedTarget 来区分聚焦或失焦事件是否源自父元素外部。这个示例展示了如何检测子元素获得焦点、父元素获得焦点,以及如何检测焦点进入或离开整个子树。

export default function FocusExample() {
  return (
    <div
      tabIndex={1}
      onFocus={(e) => {
        if (e.currentTarget === e.target) {
          console.log('focused parent');
        } else {
          console.log('focused child', e.target.name);
        }
        if (!e.currentTarget.contains(e.relatedTarget)) {
          // 在子元素之间切换焦点时不会触发
          console.log('focus entered parent');
        }
      }}
      onBlur={(e) => {
        if (e.currentTarget === e.target) {
          console.log('unfocused parent');
        } else {
          console.log('unfocused child', e.target.name);
        }
        if (!e.currentTarget.contains(e.relatedTarget)) {
          // 在子元素之间切换焦点时不会触发
          console.log('focus left parent');
        }
      }}
    >
      <label>
        名字:
        <input name="firstName" />
      </label>
      <label>
        姓氏:
        <input name="lastName" />
      </label>
    </div>
  );
}


处理键盘事件

此示例展示了一些常见的 键盘事件 以及它们何时触发。

export default function KeyboardExample() {
  return (
    <label>
      名字:
      <input
        name="firstName"
        onKeyDown={e => console.log('onKeyDown:', e.key, e.code)}
        onKeyUp={e => console.log('onKeyUp:', e.key, e.code)}
      />
    </label>
  );
}