指南

组合

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

所有渲染 DOM 元素的 Radix 原语部分都接受一个 asChild 道具。当 asChild 设置为 true 时,Radix 不会渲染默认的 DOM 元素,而是克隆部分的子元素并向其传递使之发挥作用所需的道具和行为。

更改元素类型

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

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

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

如果您确实决定更改底层元素类型,您有责任确保它仍然是可访问的且功能齐全。例如,在 Tooltip.Trigger 的情况下,它必须是一个可聚焦的元素,能够响应指针和键盘事件。如果您将其更改为 div,它将不再是可访问的。

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

与您自己的 React 组件组合

这与上面的方法完全相同,您将 asChild 传递给该部分,然后用它包装您自己的组件。但是,需要注意一些问题。

您的组件必须传播道具

当 Radix 克隆您的组件时,它将传递自己的道具和事件处理程序,以使其发挥作用并保持可访问性。如果您的组件不支持这些道具,它将崩溃。

这是通过将所有道具传播到底层 DOM 节点来完成的。

// before
const MyButton = () => <button />;
// after
const MyButton = (props) => <button {...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 * as Dialog from '@radix-ui/react-dialog';
import * as Tooltip from '@radix-ui/react-tooltip';
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>
);
};
上一页动画