常见组件(例如 <div>)

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


参考

常见组件(例如 <div>

<div className="wrapper">Some content</div>

请在下方查看更多示例。

属性

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

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

  • dangerouslySetInnerHTML:一个包含原始 HTML 字符串的对象,格式为 { __html: '<p>一些 HTML</p>' }。它会覆盖 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 将不会警告您该元素的属性和内容不匹配。它只在单层深度起作用,并且旨在用作应急方案。不要过度使用它。了解如何抑制水合错误。

  • 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(node)} />

查看使用 ref 回调的示例。

<div> DOM 节点被添加到屏幕时,React 会调用您的 ref 回调,并将 DOM 节点 作为参数。当 <div> DOM 节点被移除时,React 会调用您的 ref 回调,并将 null 作为参数。

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

参数

  • node:一个 DOM 节点或 null。当 ref 被附加时,React 会将 DOM 节点传递给您,当 ref 被分离时,React 会传递 null。除非您在每次渲染时都为 ref 回调传递相同的函数引用,否则在组件的每次重新渲染期间,回调都会被暂时分离并重新附加。

Canary

返回

  • 可选的 cleanup 函数:当 ref 被分离时,React 会调用 cleanup 函数。如果 ref 回调没有返回函数,那么当 ref 被分离时,React 会再次调用该回调,并将 null 作为参数。

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

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

注意事项

  • 当启用严格模式时,React 会在第一次真正的设置之前运行一次额外的仅限开发环境的设置+清理周期。这是一个压力测试,用于确保您的清理逻辑与您的设置逻辑“镜像”,并且它会停止或撤消设置所做的任何操作。如果这导致了问题,请实现 cleanup 函数。
  • 当您传递不同ref 回调时,如果有提供,React 会调用前一个回调的 cleanup 函数。如果没有定义 cleanup 函数,则 ref 回调将以 null 作为参数被调用。下一个函数将以 DOM 节点作为参数被调用。

React 事件对象

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

<button onClick={e => {
console.log(e); // React event object
}} />

它符合与底层 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 不同。对于 polyfilled 事件,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 处理函数

用于 剪贴板 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')}
>
Drag source
</div>

<div
onDragEnter={e => console.log('onDragEnter')}
onDragLeave={e => console.log('onDragLeave')}
onDragOver={e => { e.preventDefault(); console.log('onDragOver'); }}
onDrop={e => console.log('onDrop')}
>
Drop target
</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')}
/>

参数
  • e:一个 React 事件对象,包含以下额外的 TransitionEvent 属性

  • 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 规则

    /* In your CSS */
    .avatar {
    border-radius: 50%;
    }

    React 没有规定如何添加 CSS 文件。在最简单的情况下,您可以将 <link> 标签添加到 HTML 中。如果您使用构建工具或框架,请查阅其文档以了解如何将 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': '')} 会根据 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}>
            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) {
      // This is ONLY safe because the output HTML
      // is shown to the same user, and because you
      // trust this Markdown parser to not have bugs.
      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 = {
    // Imagine this content is stored in the database.
    content: `<img src="" onerror='alert("you were hacked")'>`
    };

    export default function MarkdownPreview() {
    // 🔴 SECURITY HOLE: passing untrusted input to 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)) {
              // Not triggered when swapping focus between children
              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)) {
              // Not triggered when swapping focus between children
              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>
      );
    }