Back to Heroui

Popover

apps/docs/content/docs/cn/react/migration/(components)/popover.mdx

3.2.17.2 KB
Original Source
<Callout type="info"> 完整的 API 参考、样式指南与高级示例请参阅 [v3 Popover 文档](/docs/react/components/popover)。本指南只关注从 HeroUI v2 的迁移。 </Callout>

结构变化

在 v2 中,Popover 由独立的多个组件组成:

tsx
import { Popover, PopoverTrigger, PopoverContent, Button } from "@heroui/react";

export default function App() {
  return (
    <Popover placement="right">
      <PopoverTrigger>
        <Button>Open</Button>
      </PopoverTrigger>
      <PopoverContent>
        <div>Content</div>
      </PopoverContent>
    </Popover>
  );
}

在 v3 中,Popover 改为复合组件:

tsx
import { Popover, Button } from "@heroui/react";

export default function App() {
  return (
    <Popover>
      <Button>Open</Button>
      <Popover.Content>
        <Popover.Dialog>
          <Popover.Heading>Title</Popover.Heading>
          <div>Content</div>
        </Popover.Dialog>
      </Popover.Content>
    </Popover>
  );
}

主要变化

1. 组件结构

v2: 独立的多个组件(PopoverPopoverTriggerPopoverContent
v3: 复合组件(PopoverPopover.TriggerPopover.ContentPopover.DialogPopover.HeadingPopover.Arrow

2. Prop 变更

v2 propv3 位置说明
placementplacement(在 Content 上)移至 Popover.Content
offsetoffset(在 Content 上)移至 Popover.Content
shouldFlipshouldFlip(在 Content 上)移至 Popover.Content
isOpen / defaultOpen / onOpenChange同名(在根上)受控状态仍保留在根 Popover
showArrow改用 Popover.Arrow 子组件
size已移除(请改用 Tailwind CSS)
color已移除(请改用 Tailwind CSS)
radius已移除(请改用 Tailwind CSS)
shadow已移除(请改用 Tailwind CSS)
backdrop已移除
motionProps已移除(动画机制已不同)
classNames改在各子组件上使用 className
onClose改用 onOpenChange((open) => { if (!open) { ... } })

迁移示例

内容配置

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Popover showArrow> <PopoverTrigger><Button>Open</Button></PopoverTrigger> <PopoverContent><div>Content</div></PopoverContent> </Popover> <Popover placement="top"> <PopoverTrigger><Button>Open</Button></PopoverTrigger> <PopoverContent><div>Content</div></PopoverContent> </Popover> <Popover offset={10}> <PopoverTrigger><Button>Open</Button></PopoverTrigger> <PopoverContent><div>Content</div></PopoverContent> </Popover> </Tab> <Tab value="v3"> tsx <Popover> <Button>Open</Button> <Popover.Content> <Popover.Dialog> <Popover.Arrow /> <div>Content</div> </Popover.Dialog> </Popover.Content> </Popover> <Popover> <Button>Open</Button> <Popover.Content placement="top"> <Popover.Dialog> <Popover.Arrow /> <div>Content</div> </Popover.Dialog> </Popover.Content> </Popover> <Popover> <Button>Open</Button> <Popover.Content offset={10}> <Popover.Dialog> <div>Content</div> </Popover.Dialog> </Popover.Content> </Popover> </Tab> </Tabs>

带标题

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <PopoverContent> <div className="px-1 py-2"> <div className="text-small font-bold">Title</div> <div className="text-tiny">Content</div> </div> </PopoverContent> </Tab> <Tab value="v3"> tsx <Popover.Content> <Popover.Dialog> <Popover.Heading>Title</Popover.Heading> <p className="text-muted mt-2 text-sm">Content</p> </Popover.Dialog> </Popover.Content> </Tab> </Tabs>

受控

<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { useState } from "react";

const [isOpen, setIsOpen] = useState(false);

<Popover isOpen={isOpen} onOpenChange={setIsOpen}>
  <PopoverTrigger>
    <Button>Open</Button>
  </PopoverTrigger>
  <PopoverContent>
    <div>Content</div>
  </PopoverContent>
</Popover>
```
</Tab> <Tab value="v3"> ```tsx import { useState } from "react";
const [isOpen, setIsOpen] = useState(false);

<Popover isOpen={isOpen} onOpenChange={setIsOpen}>
  <Button>Open</Button>
  <Popover.Content>
    <Popover.Dialog>
      <div>Content</div>
    </Popover.Dialog>
  </Popover.Content>
</Popover>
```
</Tab> </Tabs>

自定义触发器

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <PopoverTrigger> <CustomButton>Custom</CustomButton> </PopoverTrigger> </Tab> <Tab value="v3"> tsx <Popover.Trigger> <CustomButton>Custom</CustomButton> </Popover.Trigger> </Tab> </Tabs>

组件结构

v3 Popover 遵循以下结构:

Popover (Root)
  ├── Popover.Trigger (optional, or use Button directly)
  └── Popover.Content
      └── Popover.Dialog
          ├── Popover.Arrow (optional)
          ├── Popover.Heading (optional)
          └── Content

v3 中的新功能

Popover.Arrow 组件

在 v2 中,箭头通过根 Popover 上的 showArrow 布尔 prop 控制。在 v3 中,Popover.Arrow 是一个放置在 Popover.Content 内部的专用组件,让你可以完全控制其渲染:

tsx
<Popover>
  <Button>Open</Button>
  <Popover.Content>
    <Popover.Arrow className="custom-arrow" />
    <Popover.Dialog>
      <div>Content</div>
    </Popover.Dialog>
  </Popover.Content>
</Popover>

Popover.Arrow 也接受 render prop,可完全自定义箭头的渲染。

受控打开状态

受控的打开状态仍保留在根 Popover 组件上,prop 名称与 v2 一致:

属性类型默认值描述
isOpenboolean-控制 Popover 的可见性(受控)
defaultOpenbooleanfalse初始打开状态(非受控)
onOpenChange(isOpen: boolean) => void-打开状态变化时触发

自定义渲染函数

Popover.ContentPopover.Arrow 都支持 render prop,让你可以在高级场景下用自定义渲染函数覆盖默认 DOM 元素。

总结

  1. 组件结构:必须使用复合组件(Popover.ContentPopover.Dialog 等)
  2. 触发器:可以使用 Popover.Trigger,或直接将 Button 作为子节点
  3. 内容包装:内容必须放在 Popover.Dialog
  4. 箭头:移除 showArrow prop——改用 Popover.Arrow 子组件
  5. 标题:改用 Popover.Heading 组件
  6. prop 移动位置placementoffsetshouldFlip 移到 Popover.Content
  7. 移除样式 propsizecolorradiusshadow —— 请改用 Tailwind CSS
  8. 移除 backdropbackdrop prop 已移除
  9. 移除 motionmotionProps 已移除,动画机制已不同
  10. 移除 classNames:改在各子组件上使用 className prop