指南

组合

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

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

更改元素类型

在大多数情况下,您无需修改元素类型,因为 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://radix-ui.com.cn/">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 节点上来完成的。

// before
const MyButton = () => <button />;
// after
const MyButton = (props) => <button {...props} />;

我们建议始终这样做,这样您就不必担心实现细节(即,要接受哪些 props/事件)。我们发现这对于一般的“叶”组件来说是一个很好的实践。

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

您的组件必须转发 ref

此外,Radix 有时需要将 ref 附加到您的组件(例如,为了测量其大小)。如果您的组件不接受 ref,则它将崩溃。

这是使用 React.forwardRef 完成的(在 react.dev 上了解更多)。

// before
const MyButton = (props) => <button {...props} />;
// after
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>Open dialog</MyButton>
</Dialog.Trigger>
</Tooltip.Trigger>
<Tooltip.Portal></Tooltip.Portal>
</Tooltip.Root>
<Dialog.Portal>...</Dialog.Portal>
</Dialog.Root>
);
};
上一篇动画