Menu 菜单
Menu 是纵向的导航菜单,比如应用或文档站的侧边栏:带图标的行、原地展开的子菜单、带标题的分组和分割线,同时只有一行处于选中状态。它渲染成 <nav> 地标,请给它加上 aria-label。从按钮弹出的菜单请用 Dropdown。
演示
基础用法
选项是一棵树:普通行 { key, label, icon? }、子菜单(带 children 的行)、分组(type: "group")和分割线(type: "divider")。选中行所在的子菜单默认展开,包含选中行的子菜单也会被标出。
链接和路由
带 href 的行渲染成链接,选中时带 aria-current="page"。renderLink 用你的路由链接组件渲染这些行:把收到的 props 展开传进去,并保留其中的 onClick,它负责选中这一行。
收起
collapsed 把菜单收窄到 collapsedWidth,只显示图标(没有图标的行显示标签的首字母)。每一行用 tooltip 显示名称,子菜单的内容在菜单旁边的浮层里打开。
手风琴
开启 accordion 后,展开一个子菜单会收起它旁边已展开的子菜单。
受控展开
expandedKeys 和 onUpdateExpandedKeys 控制哪些子菜单展开。
缩进
rootIndent 是第一层的起始内边距,indent 是每深一层增加的缩进。默认缩进等于图标宽度加间距,这样子项的标签和父项的标签对齐。
附加内容和禁用
extra 在行尾放附加内容,比如计数。disabled 的行不能聚焦,也不能选择。
无障碍
菜单采用 disclosure 导航模式,而不是 role="menu":menu 系列角色用于命令型的应用菜单,会让读屏软件进入另一种交互模式,链接和 Tab 的行为都会改变。这里每一行都是 Tab 顺序里的普通链接或按钮;子菜单是带 aria-expanded 和 aria-controls 的按钮;分组是由标题命名的列表;选中行带 aria-current(链接上是 page,按钮上是 true)。
键盘
Tab 在各行之间移动。Enter(按钮上也可以用 Space)选择一行或展开子菜单。另外,↑ / ↓ 在可见的行之间移动,Home / End 跳到首尾,→ 展开子菜单或进入已展开的子菜单,← 收起子菜单或回到当前行所在的子菜单。
Props
| 名称 | 类型 | 默认值 | 说明 | 版本 |
|---|---|---|---|---|
options | MenuMixedOption[] | 必填 | 行、子菜单、分组和分割线,见下文。 | 未发布 |
value / defaultValue | MenuKey | null | undefined / null | 受控 / 初始的选中 key。 | 未发布 |
onUpdateValue | (key, option) => void | undefined | 选择没有子项的行时调用。 | 未发布 |
expandedKeys / defaultExpandedKeys | MenuKey[] | undefined | 受控 / 初始展开的子菜单。默认展开选中行的祖先。 | 未发布 |
defaultExpandAll | boolean | false | 初始展开全部子菜单。 | 未发布 |
onUpdateExpandedKeys | (keys: MenuKey[]) => void | undefined | 子菜单展开或收起时调用。 | 未发布 |
accordion | boolean | false | 展开子菜单时收起它已展开的兄弟子菜单。 | 未发布 |
indent / rootIndent | number | 主题 | 每层的缩进 / 第一层的起始内边距(px)。 | 未发布 |
collapsed | boolean | false | 只显示图标;标签放进 tooltip,子菜单在浮层中打开。 | 未发布 |
collapsedWidth | number | 主题(48 / 52) | 收起时的宽度(px)。 | 未发布 |
iconSize / collapsedIconSize | number | 主题 | 展开 / 收起时的图标大小(px)。 | 未发布 |
disabled | boolean | false | 禁用所有行。 | 未发布 |
renderLabel | (option) => ReactNode | undefined | 替换行和分组标题的标签。 | 未发布 |
renderLink | (props: MenuLinkProps, option) => ReactNode | undefined | 渲染带 href 的行,默认渲染 <a>。 | 未发布 |
其余 props 和 ref 传给 <nav>。
MenuOption
| 名称 | 类型 | 说明 |
|---|---|---|
key | string | number | 必填且唯一。 |
label | ReactNode | 行的文字。 |
icon | ReactNode | 在标签前面;收起时单独显示。 |
extra | ReactNode | 在行尾。 |
href | string | 让这一行成为链接。子菜单上无效。 |
disabled | boolean | 不能选择或展开。 |
show | boolean | 为 false 时不渲染该选项。 |
children | MenuMixedOption[] | 让这一行成为子菜单。 |
分组是 { type: "group", key, label, children },分割线是 { type: "divider", key }。
说明
- 目前只有
mode="vertical",横向的顶栏会单独规划。 - 标签、图标和附加内容都是
ReactNode。链接用href+renderLink,不要把路由链接塞进标签,这样整行都是链接。 - 分组里的行和分组标题处在同一缩进,和大多数文档站侧边栏一致。
accordion对每一层都生效。