NavMenu
概览
NavMenu 用于构建站点级横向或纵向导航,共享一个浮层表面。它接替了已退役的 NavigationMenu 家族(见 NavMenu 迁移指南),直接建模在 Popper 原语之上:整个 viewport 就是单个 PopperPositioner,其 reference 动态切换到激活触发器,所有悬停时序运行在单个共享 Popper 悬停状态机上,并通过 pendingValue 做值路由。
SNavMenu 是数据驱动组合:传 items 数组即可渲染 nav > ul > li 结构、触发器/内容对、指示器与浮动 viewport。样式通过 scv() recipe 注入。
需要无样式、数据驱动的用法时,导入
@vean/aria/nav-menu。
功能特性
- 单共享 Popper 模型 — 一个
PopperRoot、一个PopperPositioner(即 viewport),reference 动态切换到激活触发器。定位(Floating UI)、grace 走廊与 Escape/外部点击关闭全部由 positioner 免费提供。 - 值路由 — 悬停时序(打开延迟、跳延时窗口)运行在共享状态机上;最近悬停触发器的值路由进
modelValue,切换触发器即时完成。 - 点击 / 悬停双触发 — 默认悬停打开、点击切换;
disableClickTrigger/disableHoverTrigger可单独关闭某一种触发方式。 - Grace 走廊 — 触发器与打开的 viewport 之间由真实几何走廊保护(无防抖),
skipDelayDuration与disablePointerLeaveClose调节关闭行为。 - 子菜单浮层 — 带
children的项在其触发器旁打开浮动 viewport,支持箭头指示器与unmountOnHide控制卸载。 - 隐藏项 —
hidden将条目及其整棵子树从根列表与嵌套浮层中移除;子项全部隐藏的条目按叶子链接渲染。 - 键盘导航 — 方向键在项间移动焦点;
Enter/Space激活链接或切换子菜单;入口方向键将焦点送入内容;Escape关闭并归还焦点到触发器。 - 弹层箭头 — viewport 携带
PopperArrow指向激活触发器;其摆放与旋转由 Floating UI 的arrowmiddleware 决定,切换触发器时随 viewport 一起滑动。 - 受控 / 非受控 — 提供
modelValue时高亮跟随 prop 并触发update:modelValue;否则用defaultValue做非受控初始值。 - 双向支持 —
orientation支持横向 / 纵向;dir支持 LTR / RTL 逻辑定位。 - 六档尺寸 —
size(xs…2xl)覆盖列表、触发器、viewport 与链接的间距和字号。 - Aria 组合 —
NavMenuRoot/List/Item/Trigger/Content/Link/Viewport及Compact系列由@vean/aria/nav-menu导出。
用法
示例
Basic
Nested
API
Aria 层
12NavMenu
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
class | ClassValue | — | 应用于根元素的额外类名。 |
size | ThemeSize | — | 组件的视觉尺寸。 |
ui | Partial<NavMenuUi> | — | 该组件的按槽类重写。 |
items | NavMenuOptionData[] | — | 导航菜单中要渲染的项目。 |
modelValue | string | — | 活动项的受控值。可作为 `v-model` 使用。 |
defaultValue | string | — | 初始渲染时应处于活动状态的项的值。 |
dir | Direction | — | 菜单的阅读方向。 |
orientation | DataOrientation | — | 菜单的排列方向。 |
delayDuration | number | 200 | 从指针进入触发区到子菜单打开所花费的时间。 |
skipDelayDuration | number | 300 | 用户在触发延迟之前,有多少时间可以输入另一个触发条件。 |
disableClickTrigger | boolean | false | 如果设置为 `true`,则无法通过点击触发器打开菜单。 |
disableHoverTrigger | boolean | false | 如果设置为 `true`,则无法通过将鼠标悬停在触发器上打开菜单。 |
disablePointerLeaveClose | boolean | false | 如果设置为 `true`,当指针移出内容区域时,菜单不会关闭。 |
itemProps | NavMenuItemProps | — | 转发给 item 元素的属性。 |
linkProps | Omit<NavMenuLinkProps, LinkBasePropsKey> | — | 传递给 link 元素的属性。 |
subTriggerProps | NavMenuSubTriggerProps | — | 转发给嵌套弹出触发元素的属性。 |
subContentProps | NavMenuSubContentProps | — | 转发给嵌套的 flyout 内容元素的属性。 |
triggerProps | NavMenuTriggerProps | — | 转发给触发元素的属性。 |
contentProps | NavMenuContentProps | — | 转发给内容元素的属性。 |
listProps | NavMenuListProps | — | 转发给列表元素的属性。 |
viewportProps | NavMenuViewportProps | — | 转发给视口元素的属性。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:modelValue | string | 当模型值发生变化时触发。 |
select | CustomEvent<{ originalEvent: Event; }> | 当选中链接时触发。 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
item | props: { item: NavMenuOptionData; isTrigger?: boolean; } | — |
item-leading | props: { item: NavMenuOptionData; } | — |
item-trailing | props: { item: NavMenuOptionData; } | — |
item-link-icon | props: { item: NavMenuOptionData; } | — |
item-trigger-icon | props: { item: NavMenuOptionData; } | — |
item-children | props: { item: NavMenuOptionData; } | — |
NavMenuCompact
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
items | NavMenuOptionData[] | — | 导航菜单中要渲染的项目。 |
modelValue | string | — | 活动项的受控值。可作为 `v-model` 使用。 |
defaultValue | string | — | 初始渲染时应处于活动状态的项的值。 |
dir | Direction | — | 菜单的阅读方向。 |
orientation | DataOrientation | — | 菜单的排列方向。 |
delayDuration | number | 200 | 从指针进入触发区到子菜单打开所花费的时间。 |
skipDelayDuration | number | 300 | 用户在触发延迟之前,有多少时间可以输入另一个触发条件。 |
disableClickTrigger | boolean | false | 如果设置为 `true`,则无法通过点击触发器打开菜单。 |
disableHoverTrigger | boolean | false | 如果设置为 `true`,则无法通过将鼠标悬停在触发器上打开菜单。 |
disablePointerLeaveClose | boolean | false | 如果设置为 `true`,当指针移出内容区域时,菜单不会关闭。 |
itemProps | NavMenuItemProps | — | 转发给 item 元素的属性。 |
linkProps | Omit<NavMenuLinkProps, LinkBasePropsKey> | — | 传递给 link 元素的属性。 |
subTriggerProps | NavMenuSubTriggerProps | — | 转发给嵌套弹出触发元素的属性。 |
subContentProps | NavMenuSubContentProps | — | 转发给嵌套的 flyout 内容元素的属性。 |
triggerProps | NavMenuTriggerProps | — | 转发给触发元素的属性。 |
contentProps | NavMenuContentProps | — | 转发给内容元素的属性。 |
listProps | NavMenuListProps | — | 转发给列表元素的属性。 |
viewportProps | NavMenuViewportProps | — | 转发给视口元素的属性。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:modelValue | string | 当模型值发生变化时触发。 |
select | CustomEvent<{ originalEvent: Event; }> | 当选中链接时触发。 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
item | props: { item: NavMenuOptionData; isTrigger?: boolean; } | — |
item-leading | props: { item: NavMenuOptionData; } | — |
item-trailing | props: { item: NavMenuOptionData; } | — |
item-link-icon | props: { item: NavMenuOptionData; } | — |
item-trigger-icon | props: { item: NavMenuOptionData; } | — |
item-children | props: { item: NavMenuOptionData; } | — |
NavMenuContent
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
forceMount | boolean | — | 用于在需要更多控制时强制挂载。
在使用 Vue 动画库控制动画时非常有用。 |
NavMenuItem
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
value | string | — | 与当前项关联的值。 |
NavMenuLink
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
selected | boolean | — | 将该链接标记为当前选中的页面。 |
sub | boolean | — | 链接是否渲染在子菜单中。当值为 `true` 时,将使用 `subLink` UI 插槽
代替 `link`(与列表的根/子菜单划分相对应)。 |
replace | boolean | — | 调用 `router.replace` 而不是 `router.push`。 |
disabled | boolean | — | 当值为 `true` 时,该链接将被禁用。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
href | string | — | 点击链接时应跳转到的 URL。 |
to | string | import("vue-router").RouteLocationAsRelativeGeneric | import("vue-router").RouteLocationAsPathGeneric | — | Route Location:点击该链接后应跳转到的位置。 |
activeClass | string | — | 当链接处于活动状态时应用的类 |
exactActiveClass | string | — | 当链接完全有效时应用的类 |
inactiveClass | string | — | 链接处于非活动状态时应应用的类。 |
prefetchedClass | string | — | 一个用于标记已预取链接的类。 |
external | boolean | — | 强制将链接视为外部链接(true)或内部链接(false)。这有助于处理边界情况 |
ariaCurrentValue | 'true' | 'false' | 'page' | 'date' | 'time' | 'step' | 'location' | `'page'` | 当链接处于活动状态时,传递给 `aria-current` 属性的值。 |
viewTransition | boolean | — | 如果支持,请将 `router.push()` 返回的 Promise 传递给 `document.startViewTransition()`。 |
target | (string & {}) | '_blank' | '_parent' | '_self' | '_top' | null | — | 将链接的 URL 作为浏览上下文的名称显示在何处。 |
rel | (string & {}) | 'noopener' | 'noreferrer' | 'nofollow' | 'sponsored' | 'ugc' | null | 'noopener noreferrer' | 应用于链接的 rel 属性值。对于外部链接,默认值为“noopener noreferrer”。 |
noRel | boolean | — | 如果设置为 true,则不会在链接中添加 rel 属性 |
prefetch | boolean | — | 启用后,将预取视口内链接的中间件、布局和有效载荷。 |
prefetchOn | 'visibility' | 'interaction' | Partial<{ visibility: boolean; interaction: boolean; }> | — | 允许控制何时预取链接。默认情况下,仅在可见性发生变化时才会触发预取。 |
noPrefetch | boolean | — | 用于禁用 `prefetch` 属性的逃逸机制。 |
trailingSlash | 'append' | 'remove' | — | 一个用于在此特定链接的 `href` 中添加或移除尾部斜杠的选项。
如果提供了此选项,将覆盖全局 `trailingSlash` 选项。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
select | CustomEvent<{ originalEvent: Event; }> | 当选中链接时触发。 |
NavMenuList
NavMenuOptionCompact
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
item | NavMenuOptionData | — | 当前条目数据。 |
itemProps | NavMenuItemProps | — | 转发给 item 元素的属性。 |
linkProps | Omit<NavMenuLinkProps, LinkBasePropsKey> | — | 传递给 link 元素的属性。 |
triggerProps | NavMenuTriggerProps | — | 转发给触发元素的属性。 |
contentProps | NavMenuContentProps | — | 转发给内容元素的属性。 |
viewportProps | NavMenuViewportProps | — | 转发给视口元素的属性。 |
listProps | NavMenuListProps | — | 转发给列表元素的属性。 |
subTriggerProps | NavMenuSubTriggerProps | — | 转发给嵌套弹出触发元素的属性。 |
subContentProps | NavMenuSubContentProps | — | 转发给嵌套的 flyout 内容元素的属性。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
select | CustomEvent<{ originalEvent: Event; }> | 当选中链接时触发。 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
item | props: { item: NavMenuOptionData; isTrigger?: boolean; } | — |
item-leading | props: { item: NavMenuOptionData; } | — |
item-trailing | props: { item: NavMenuOptionData; } | — |
item-link-icon | props: { item: NavMenuOptionData; } | — |
item-trigger-icon | props: { item: NavMenuOptionData; } | — |
item-children | props: { item: NavMenuOptionData; } | — |
NavMenuRoot
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
modelValue | string | — | 活动项的受控值。可作为 `v-model` 使用。 |
defaultValue | string | — | 初始渲染时应处于活动状态的项的值。 |
dir | Direction | — | 菜单的阅读方向。 |
orientation | DataOrientation | — | 菜单的排列方向。 |
delayDuration | number | 200 | 从指针进入触发区到子菜单打开所花费的时间。 |
skipDelayDuration | number | 300 | 用户在触发延迟之前,有多少时间可以输入另一个触发条件。 |
disableClickTrigger | boolean | false | 如果设置为 `true`,则无法通过点击触发器打开菜单。 |
disableHoverTrigger | boolean | false | 如果设置为 `true`,则无法通过将鼠标悬停在触发器上打开菜单。 |
disablePointerLeaveClose | boolean | false | 如果设置为 `true`,当指针移出内容区域时,菜单不会关闭。 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:modelValue | string | 当模型值发生变化时触发。 |
NavMenuSubContent
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
sideOffset | number | — | 子触发器与嵌套弹出菜单之间的像素距离。 |
forceMount | boolean | — | 用于在需要更多控制时强制挂载。
在使用 Vue 动画库控制动画时非常有用。 |
NavMenuSubTrigger
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
disabled | boolean | — | 触发器是否已禁用。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
NavMenuTrigger
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
disabled | boolean | — | 触发器是否已禁用。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
NavMenuViewport
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
align | Align | — | 将视口与活动触发器对齐。 |
sideOffset | number | — | 触发器与视口之间的距离(以像素为单位)。 |
forceMount | boolean | — | 用于在需要更多控制时强制挂载。
在使用 Vue 动画库控制动画时非常有用。 |
注意事项
架构
| 能力 | NavMenu(Popper 原生) |
|---|---|
| 浮层模型 | 单 PopperRoot + viewport 即 PopperPositioner |
| 定位 | Floating UI 锚定激活触发器(动态 reference) |
| 悬停延迟 | 共享 Popper 悬停状态机(delayDuration / skipDelayDuration) |
| grace 走廊 | positioner 的 useGraceArea 锚定整个 nav |
| 关闭 | positioner 的 usePopperDismiss(Escape / 外部点击) |
| 值路由 | 共享 RootContext 上的 pendingValue 槽 |
运行时注意事项
- 悬停时序 — 菜单在悬停
delayDuration后打开;已打开(或上次关闭后skipDelayDuration内)时悬停另一触发器即时切换。disablePointerLeaveClose让指针离开内容时保持打开。 - 点击与悬停互斥 — 悬停打开的子菜单会忽略随后的 click(
hasPointerMoveOpenedRef守卫),避免“移动时误关闭”。需要纯点击体验时设置disableHoverTrigger: true。 - 受控 / 非受控 — 提供
modelValue时,内部写入仅触发update:modelValue;高亮完全跟随 prop。 - 焦点处理 — 内容通过焦点代理参与 Tab 导航;
Escape将焦点归还激活触发器。
FAQ
NavMenu 与已退役的 NavigationMenu 家族有何不同?
NavMenu 放弃了共享测量尺寸的 viewport 与每项 hover root,改用 Popper 原生的单 Root + positioner 模型:Floating UI 定位 viewport,grace 走廊与关闭来自 positioner。代价是用标准浮动弹层取代了旧的尺寸/移动方向动画。NavigationMenu 与 SNavigationMenu 已于 v0.50.0 移除——见迁移指南。
如何只保留点击触发?
设置 disableHoverTrigger: true —— 悬停不再打开子菜单,点击仍可切换。只要悬停则设置 disableClickTrigger: true。
父项可以既是链接又带子菜单吗?
可以 —— 同时给项 href / to 与 children。触发器会渲染为链接;点击已打开的链接触发器会先关闭菜单。