组合
用组件组合模式搭建灵活 UI
HeroUI Native 通过组合模式实现灵活、可定制的组件:可更换实际渲染元素、将多个部件拼在一起,并完全掌控结构。
复合组件
HeroUI Native 采用点记法的复合组件——子组件作为属性导出(如 Button.Label、Dialog.Trigger、Accordion.Item),共同构成完整界面。
import { Button, Dialog } from 'heroui-native';
function DialogExample() {
return (
<Dialog>
<Dialog.Trigger>
打开对话框
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Close />
<Dialog.Title>对话框标题</Dialog.Title>
<Dialog.Description>对话框说明</Dialog.Description>
</Dialog.Content>
</Dialog.Portal>
</Dialog>
);
}asChild 属性
asChild 用于改变组件实际渲染的元素。为 true 时,HeroUI Native 会克隆子元素并合并属性,而不是渲染默认包裹节点。
import { Button, Dialog } from 'heroui-native';
function DialogExample() {
return (
<Dialog>
{/* asChild:Button 直接作为触发器,无额外包裹 */}
<Dialog.Trigger asChild>
<Button variant="primary">打开对话框</Button>
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
{/* Dialog.Close 也可使用 asChild */}
<Dialog.Close asChild>
<Button variant="ghost" size="sm">取消</Button>
</Dialog.Close>
<Dialog.Title>对话框标题</Dialog.Title>
<Dialog.Description>对话框说明</Dialog.Description>
</Dialog.Content>
</Dialog.Portal>
</Dialog>
);
}自定义组件
通过组合 HeroUI Native 原语封装自己的组件:
import { Button, Card, Popover } from 'heroui-native';
import { View } from 'react-native';
// 商品卡片
function ProductCard({ title, description, price, onBuy, ...props }) {
return (
<Card {...props}>
<Card.Body>
<Card.Title>{price}</Card.Title>
<Card.Title>{title}</Card.Title>
<Card.Description>{description}</Card.Description>
</Card.Body>
<Card.Footer>
<Button variant="primary" onPress={onBuy}>
<Button.Label>立即购买</Button.Label>
</Button>
</Card.Footer>
</Card>
);
}
// 带 Popover 的按钮
function PopoverButton({ children, popoverContent, ...props }) {
return (
<Popover>
<Popover.Trigger asChild>
<Button {...props}>
<Button.Label>{children}</Button.Label>
</Button>
</Popover.Trigger>
<Popover.Portal>
<Popover.Overlay />
<Popover.Content>
<Popover.Close />
{popoverContent}
</Popover.Content>
</Popover.Portal>
</Popover>
);
}
// 用法
<ProductCard
title="客厅沙发"
description="适合现代家居空间"
price="$450"
onBuy={() => console.log('购买')}
/>
<PopoverButton variant="tertiary" popoverContent={
<View>
<Popover.Title>说明</Popover.Title>
<Popover.Description>更多详情见此处</Popover.Description>
</View>
}>
显示说明
</PopoverButton>自定义变体
可用 tailwind-variants 扩展样式。文字颜色类须加在 Button.Label 上,而不是父级 Button:
import { Button } from 'heroui-native';
import type { ButtonRootProps } from 'heroui-native';
import { tv, type VariantProps } from 'tailwind-variants';
const customButtonVariants = tv({
base: 'font-semibold rounded-lg',
variants: {
intent: {
primary: 'bg-blue-500',
secondary: 'bg-gray-200',
danger: 'bg-red-500',
},
},
defaultVariants: {
intent: 'primary',
},
});
const customLabelVariants = tv({
base: '',
variants: {
intent: {
primary: 'text-white',
secondary: 'text-gray-800',
danger: 'text-white',
},
},
defaultVariants: {
intent: 'primary',
},
});
type CustomButtonVariants = VariantProps<typeof customButtonVariants>;
interface CustomButtonProps
extends Omit<ButtonRootProps, 'className' | 'variant'>,
CustomButtonVariants {
className?: string;
labelClassName?: string;
}
export function CustomButton({
intent,
className,
labelClassName,
children,
...props
}: CustomButtonProps) {
return (
<Button
className={customButtonVariants({ intent, className })}
{...props}
>
<Button.Label
className={customLabelVariants({ intent, className: labelClassName })}
>
{children}
</Button.Label>
</Button>
);
}