Guides

组合

使用 asChild 属性将 Radix 的功能组合到替代元素类型或您自己的 React 组件中。

所有渲染 DOM 元素的 Radix 原始部分都接受 asChild 属性。当 asChild 设置为 true 时,Radix 将不会渲染默认的 DOM 元素,而是克隆该部分的子元素,并将所需的 props 和行为传递给它以使其功能正常。

更改元素类型

在大多数情况下,您无需修改元素类型,因为 Radix 的设计目标是提供最合适的默认值。但是,有些情况下这样做是有帮助的。

一个很好的例子是 Tooltip.Trigger。默认情况下,此部分渲染为一个 button,但您可能还想将提示添加到链接(a 标签)。让我们看看如何使用 asChild 来实现这一点:

import * as React from "react";
import { Tooltip } from "radix-ui";
export default () => (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<a href="https://www.radix-ui.com/">Radix UI</a>
</Tooltip.Trigger>
<Tooltip.Portal></Tooltip.Portal>
</Tooltip.Root>
);

如果您决定更改底层元素类型,确保它保持可访问和功能正常是您的责任。以 Tooltip.Trigger 为例,它必须是一个可获取焦点的元素,可以响应指针和键盘事件。如果您将其切换为 div,则将不再可访问。

实际上,您很少会像上面那样修改底层 DOM 元素。相反,使用您自己的 React 组件更为常见。对于大多数 Trigger 部分尤其如此,因为您通常希望将功能与设计系统中的自定义按钮和链接组合在一起。

使用您自己的 React 组件组合

这与上述内容完全相同,您只需将 asChild 传递给部分,然后用您自己的组件将其包装起来。不过,有一些需要注意的事项。

您的组件必须传播 props

当 Radix 克隆您的组件时,它将传递自己的 props 和事件处理程序以使其功能和可访问。如果您的组件不支持这些 props,它将会失败。

这一操作是通过将所有 props 展开到底层 DOM 节点上来完成的。

// 之前
const MyButton = () => <button />;
// 之后
const MyButton = (props) => <button {...props} />;

我们建议始终这样做,以免担心实现细节(例如,接受哪些 props/事件)。我们发现这对于“叶子”组件而言是良好的实践。

与直接更改元素类型类似,确保由您的自定义组件渲染的元素类型保持可访问和功能正常也是您的责任。

您的组件必须转发 ref

此外,Radix 有时需要将一个 ref 附加到您的组件(例如,用于测量其大小)。如果您的组件不接受 ref,那么它将会失败。

这可以使用 React.forwardRef 来完成(详细了解请访问 react.dev)。

// 之前
const MyButton = (props) => <button {...props} />;
// 之后
const MyButton = React.forwardRef((props, forwardedRef) => (
<button {...props} ref={forwardedRef} />
));

虽然这并非对 所有 部分都是必要的,但我们建议始终这样做,以免担心实现细节。这通常也是良好的实践,尤其是对于叶子组件。

组合多个原始组件

asChild 可以被用作您需要的深度。这意味着它是组合多个原始组件行为的绝佳方式。 以下是如何将 Tooltip.TriggerDialog.Trigger 与您自己的按钮组合在一起的示例:

import * as React from "react";
import { Dialog, Tooltip } from "radix-ui";
const MyButton = React.forwardRef((props, forwardedRef) => (
<button {...props} ref={forwardedRef} />
));
export default () => {
return (
<Dialog.Root>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Dialog.Trigger asChild>
<MyButton>打开对话框</MyButton>
</Dialog.Trigger>
</Tooltip.Trigger>
<Tooltip.Portal></Tooltip.Portal>
</Tooltip.Root>
<Dialog.Portal>...</Dialog.Portal>
</Dialog.Root>
);
};