InfiniteMenu
infinite-menu可拖拽旋转的菜单球,菜单项围绕球面分布、正对镜头者贴靠为激活项并显覆盖层标题/描述+动作箭头 · 松手惯性衰减 + 自动自旋(零依赖 CSS-3D/RAF·reduced-motion)
用法
基础用法
items 围绕球面均匀排布,可拖拽旋转;正对镜头的项为激活项,其标题 / 描述显示在覆盖层。省略 image 时卡片显示标题首字。
概览
项目全局视图
tsx
<div
className="relative h-80 overflow-hidden rounded-xl"
style={{ background: "oklch(0.16 0.02 255)" }}
>
<InfiniteMenu
items={[
{ title: "概览", description: "项目全局视图" },
{ title: "任务", description: "进行中的工作流" },
{ title: "成员", description: "团队与权限" },
]}
/>
</div>放大球体 · 大卡片
scale 拉近球体、itemSize 放大单卡直径。
概览
项目全局视图
tsx
<InfiniteMenu items={items} scale={1.15} itemSize={104} />关闭自动旋转
autoRotate={0} 关闭自旋,球体仅在拖拽时转动。
概览
项目全局视图
tsx
<InfiniteMenu items={items} autoRotate={0} />何时用
把一组导航入口/画廊项做成可拖拽探索的球面菜单(创意首页、作品集导航)时用。要的是"球面分布 + 拖拽旋转 + 贴靠激活"的探索式导航用本组件;只展示一组海报飞行长廊用 FlyingPosters,单卡 3D 倾斜用 TiltedCard。
导入
ts
import { InfiniteMenu } from "@hulianui/ui"Props
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
| items | InfiniteMenuItem[] | [] | 菜单项数组,沿球面 Fibonacci 均匀分布;正对镜头的项为激活项并在覆盖层显其标题/描述。空数组渲占位球 |
| scale | number | 1 | 球体缩放系数,越大球越近、单卡越大 |
| itemSize | number | 88 | 单张卡片直径(px) |
| autoRotate | number | 6 | 自动旋转角速度(度/秒,绕 Y 轴),0 关闭;拖拽时暂停,松手惯性衰减后恢复;reduced-motion 下强制为 0 |
| className | string | — | 透传到根容器的额外类名 |
| style | CSSProperties | — | 透传到根容器的内联样式 |
Events
| 事件 | 类型 | 说明 |
|---|---|---|
| onActiveItemChange | (item: InfiniteMenuItem, index: number) => void | 激活项变化回调(拖拽停止贴靠到最前项后触发) |
| onItemActivate | (item: InfiniteMenuItem, index: number) => void | false | 点击激活项动作箭头回调,返回 false 阻止默认 window.open |
InfiniteMenuItem:{ image?: string; title?: string; description?: string; link?: string } —— link 以 http 开头则 window.open 新标签,否则交给 onItemActivate 处理;image 省略时仅显示标题首字。
禁忌 / 坑
- 根容器需有明确尺寸(球按容器测量布局),否则球不可见或塌缩。
link不以 http 开头时不会自动跳转,须自行在onItemActivate里处理(如router.push)。- 纯 CSS-3D + RAF 零依赖,但仍是交互动效组件:reduced-motion 下自动停自旋;headless 截图可能停在某一帧,验交互态用真实浏览器。
相关
Table · Book3D · ProTable · PricingTable · JsonViewer · EditableTable
Playground
概览
项目全局视图
<div className="relative h-80 overflow-hidden rounded-xl"
style={{ background: "oklch(0.16 0.02 255)" }}>
<InfiniteMenu
items={items}
scale={1}
itemSize={88}
autoRotate={6}
/>
</div>