普通组件(例如 <div>)

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


参考

通用组件(例如 <div>

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

参见下方更多示例

属性

这些特殊的 React 属性适用于所有内置组件:

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

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

  • ref:使用 useRef 或者 createRef 的 ref 对象,或者一个 ref 回调函数,再或者一个用于 传统 ref 的字符串。ref 将被填充为此节点的 DOM 元素。阅读更多关于使用 ref 操纵 DOM 的内容

  • suppressContentEditableWarning:布尔值。如果为 true 将会抑制 React 对同时具有 childcontentEditable={true} 属性的元素发出的警告(这两者通常不能同时使用)。如果你正在构建一个手动管理 contentEditable 内容的文本输入库,请使用此选项。

  • suppressHydrationWarning:布尔值。如果你使用 服务器渲染,通常会在服务器和客户端渲染不同内容时发出警告。在一些罕见的情况下(比如时间戳),很难或者不可能保证完全匹配。如果你设置 suppressHydrationWarningtrue,React 不会在元素属性和内容不匹配时发出警告。它只能在同级工作,并被作为应急方案。阅读有关抑制 hydrate 错误的内容

  • style:CSS 样式对象,如 { fontWeight:'bold',margin:20 }。与 DOM style 属性类似,CSS 属性应该使用像 camelCase 这样的驼峰命名法,如应该使用 fontWeight 而不是 font-weight。你可以将字符串或数字作为值传递,类似 width: 100,React 会自动将值附加为 px(“像素”),除非它是一个 无单位的属性。我们建议仅在动态样式中使用 style,即事先不知道样式值。在其他情况下,使用普通的 CSS 类和 className 更有效。了解有关 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 回调函数

useRef 返回的 ref 对象不同,可以将函数传递给 ref 属性。

<div ref={(node) => console.log(node)} />

查看使用 ref 回调函数的示例

<div> DOM 节点被添加到屏幕上时,React 将使用该节点作为参数调用 ref 回调函数。

当传递不同的ref回调时,React 也会调用 ref 回调。在上面的示例中,(node) => { ... } 在每次渲染时都是一个不同的函数。当组件重新渲染时,先前的函数将被调用并传递 null 作为参数,并且下一个函数将被调用并传递对应 DOM 节点作为参数。

参数

  • node:DOM 节点或 null。当回调函数被附加在 ref 属性后,触发回调时,该参数为对应的 DOM 节点。当 ref 被分离时值为 null。除非在每次渲染时都传递相同的函数引用作为 ref 回调,否则该回调将在组件的每次重新渲染期间被暂时分离和重新连接。

返回值

不要从 ref 回调函数中返回任何内容。


React 事件对象

你的事件处理程序将接收到一个 React 事件对象。它有时也被称为“合成事件”(synthetic event)。

<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(原生事件类型)不同。

AnimationsEvent 处理函数

一个用于 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 Drag 和 Drop 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')}
/>

看一个例子

参数

它还包括继承的 UIEvent 属性:


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')}
/>

看一个例子

参数

它还包括继承的 UIEvent 属性:


TouchEvent 处理函数

一个用于 触摸事件 的事件处理程序类型。

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

参数

它还包括继承的 UIEvent 属性:


TransitionEvent 处理函数

一个用于 CSS 过渡的事件处理程序类型。

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

参数


UIEvent 处理函数

一个通用 UI 事件的事件处理程序类型。

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

参数


WheelEvent 处理函数

一个用于 onWheel 事件的事件处理程序类型。

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

参数

它还包括继承的 MouseEvent 属性:

它还包括继承的 UIEvent 属性:


用法

应用 CSS 样式

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

<img className="avatar" />

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

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

在最简单的情况下,你可以将 <link> 标签添加到 HTML 中。如果你使用构建工具或框架,请查阅其文档以了解如何将 CSS 文件添加到项目中。React 不规定如何添加 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={'Photo of ' + user.name}
      className="avatar"
      style={{
        width: user.imageSize,
        height: user.imageSize
      }}
    />
  );
}

深入探讨

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

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

例如,className={'row ' + (isSelected ? 'selected':'')} 将会生成 className="row" 还是 className="row selected" 取决于 isSelected 是否为 true

使用像 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}>
        Focus the input
      </button>
    </>
  );
}

阅读更多关于 使用 ref 操纵 DOM 的内容并 查看更多示例

对于更高级的用例,ref 属性还可以接受 回调函数


危险地设置内部 HTML

你可以像这样将原始的 HTML 字符串传递给元素:

const markup = { __html:'<p>some raw html</p>' };
return <div dangerouslySetInnerHTML={markup} />;

这很危险。与底层的 DOM innerHTML 属性一样,你必须极度谨慎!除非标记语言来自完全可信的来源,否则通过这种方式引入 XSS 是容易被攻击的

例如,如果你使用将 Markdown 转换为 HTML 的 Markdown 库,你得相信它的解析器没有漏洞,用户只能看到自己的输入,你可以像这样显示生成的 HTML:

import { Remarkable } from 'remarkable';

const md = new Remarkable();

function renderMarkdownToHTML(markdown) {
  // 这里安全的原因是输出的 HTML 代码
  // 仅显示给同一用户,
  // 并且你信任此 Markdown 解析器没有漏洞。
  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("你被入侵了")'>`
};

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)')}
      >
        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)')}
      >
        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' }}
      >
        First child
      </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' }}
      >
        Second child
      </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>
        First name:
        <input name="firstName" />
      </label>
      <label>
        Last name:
        <input name="lastName" />
      </label>
    </div>
  );
}


处理键盘事件

这个例子展示了一些常见的 键盘事件 以及它们触发的时机。

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