Nuxt UI 导航模式实战:Header、侧边栏、面包屑与页内 Tab 导航完整指南

原创2026-10-08 21:06:581,764 阅读
文章标签:前端UI组件设计系统

Nuxt UI 导航模式实战:Header、侧边栏、面包屑与页内 Tab 导航完整指南

本文基于 Nuxt UI(The Intuitive Vue UI Library,构建于 Reka UI 与 Tailwind CSS 之上)的导航配方文档,系统梳理四种最常见导航形态:带移动端菜单的顶栏 Header、Dashboard 可折叠侧边栏、动态面包屑,以及页内 Tab 导航。你将学会如何用 UHeader、UNavigationMenu、UBreadcrumb、UTabs 组装出完整的应用导航骨架,并理解它们底层对插槽、分组数据模型与折叠状态的实现细节,做到开箱即用、可深度定制。

导航组件的全景定位

在 Nuxt UI 的组件体系中,导航相关能力分布在 Layout(布局) 与 Navigation(导航) 两个分类下。本文涉及的四个核心组件职责如下:

组件 用途
UHeader 响应式页头,内置桌面导航与移动端菜单
UNavigationMenu 主导航菜单,支持水平 / 垂直两种形态与折叠态
UBreadcrumb 面包屑,展示页面层级位置
UTabs 页面内部 Tab 切换器

其中 UNavigationMenu 是贯穿 Header、Sidebar、Footer 的"通用导航引擎",在 Footer.vue 中它被用来渲染页脚链接,在 header.md 与 footer.md 文档中均被反复引用,足以说明其在导航体系中的核心地位。

Header:桌面导航 + 移动端菜单

UHeader 的插槽约定非常直观:默认插槽渲染桌面端导航,#body 插槽则是移动端菜单内容。如果省略 #body,移动端用户将完全没有导航入口 —— 这是该组件最常见的误用点。

<UHeader>
  <template #title>
    <Logo class="h-6 w-auto" />
  </template>

  <UNavigationMenu :items="items" />

  <template #right>
    <UColorModeButton />
    <UButton label="Sign in" color="neutral" variant="ghost" />
  </template>

  <template #body>
    <UNavigationMenu :items="items" orientation="vertical" class="-mx-2.5" />
  </template>
</UHeader>

插槽与关键属性解析

查看 Header.vue 的插槽定义 可知,UHeader 共暴露 10 个插槽,其中与导航最相关的几个是:

  • title:标题区域,内部默认包装为指向 to 属性的 ULink,可通过 title / to prop 配置;
  • default(center):桌面导航区,lg 断点以上显示(见 theme/header.ts 中 center: 'hidden lg:flex');
  • right:右侧操作区,如颜色模式切换、登录按钮;
  • body:移动端菜单内容,渲染在 mode 指定的弹出容器内;
  • content:自定义整个移动端菜单内容(优先级高于 body)。

UHeader 还提供以下常用 props(详见 HeaderProps 定义):

Prop 默认值 说明
mode 'modal' 移动端菜单的呈现方式:'modal' / 'slideover' / 'drawer'
toggle true 是否显示菜单开关按钮,传对象可覆盖按钮 props
toggleSide 'right' 开关按钮放在左侧还是右侧
autoClose true 路由变化时自动关闭菜单(源码中用 watch(() => route.fullPath) 实现,见 Header.vue)
title / to 'Nuxt UI' / '/' 标题文本与点击跳转地址

在移动端菜单内部,#title 与 #right 的内容会被复用到弹出层的头部,确保移动端菜单同样拥有完整的品牌与操作区。

常见的 Header 误区

  • 忘记 #body 插槽:移动端将没有导航菜单,这是 landing 布局文档 明确强调的第一大坑;
  • Header 与 Hero 按钮都使用 variant="solid":Header 内的按钮应当比页面主 CTA 视觉权重更低,建议使用 ghost 或 subtle 变体。

完整的应用外壳(UHeader + UMain + UFooter + UPageHero 等)示例见 landing 布局。

Sidebar:Dashboard 可折叠侧边栏导航

Dashboard 场景下,侧边栏导航由 UDashboardSidebar 与 UNavigationMenu 协作完成,完整模式可参考 dashboard 布局。这里提炼三个关键点:

1. 始终传递 :collapsed="collapsed"

在可折叠侧边栏中,UNavigationMenu 必须接收 collapsed 状态。从源码看,collapsed 仅对 orientation="vertical" 生效(NavigationMenu.vue 注释明确 Only works when orientation is vertical),其视觉表现由主题中的 compoundVariants 控制:折叠时自动隐藏标签与尾随图标、收缩内边距(见 theme/navigation-menu.ts 中 orientation: 'vertical', collapsed: true 组合)。

<UDashboardSidebar collapsible resizable>
  <template #default="{ collapsed }">
    <UNavigationMenu
      :collapsed="collapsed"
      :items="items"
      orientation="vertical"
    />
  </template>
</UDashboardSidebar>

折叠态还自动带来两个附加能力:

  • Tooltip:当 tooltip prop 开启时,折叠后的图标项会显示右侧 tooltip(默认 { delayDuration: 0, content: { side: 'right' } });
  • Popover 子菜单:当 popover prop 开启时,折叠态的父级项点击后会在右侧弹出子菜单(默认 { mode: 'hover', side: 'right', align: 'start' })。

这两项默认参数均可在 NavigationMenu.vue 源码中找到。

2. 用 NavigationMenuItem[][] 组织导航分组

UNavigationMenu 的 items 支持一维数组(单个列表)与二维嵌套数组(多个分组)。源码中通过 isArrayOfArray 判断:

const lists = computed<NavigationMenuItem[][]>(() =>
  props.items?.length
    ? isArrayOfArray(props.items)
      ? props.items
      : [props.items]
    : []
)

二维数组的典型用途是:主导航一组 + 页脚链接一组,组与组之间会自动渲染分隔线(源码中 orientation === 'vertical' 时插入 separator 节点)。分组模式下,每个 item 的默认 value 会带上 group-${listIndex}- 前缀,避免跨组冲突(见 getItemValue)。

3. 用 #footer 插槽放置用户菜单

UDashboardSidebar 的 #footer 插槽专门用于放置用户菜单,配合 UDropdownMenu 实现"头像 + 退出登录"等操作。插槽会接收到 { collapsed, collapse } 参数,collapsed 为布尔折叠状态,collapse(value) 用于编程式切换 —— 折叠时你可以只显示图标、隐藏文字:

<template #footer="{ collapsed }">
  <UButton
    :icon="collapsed ? 'i-lucide-log-out' : undefined"
    :label="collapsed ? undefined : 'Sign out'"
    color="neutral"
    variant="ghost"
    block
  />
</template>

UNavigationMenu 的 item 数据模型非常丰富,除 label、icon、to 外,还支持 avatar、badge、chip、tooltip、popover、trailingIcon、type('label' | 'trigger' | 'link')、slot、value、children(嵌套子项)、defaultOpen 等字段,完整定义见 NavigationMenuItem 接口。测试用例中对 orientation: 'vertical'、collapsed: true 等组合均有覆盖验证(见 NavigationMenu.spec.ts)。

Breadcrumb:从当前路由动态生成面包屑

面包屑的核心诉求是"反映用户当前所处位置"。最实用的做法是直接从 route.path 拆分出路径分段,并组装成 UBreadcrumb 的 items:

<script setup lang="ts">
const route = useRoute()

const breadcrumbs = computed(() => {
  const segments = route.path.split('/').filter(Boolean)
  return segments.map((segment, index) => ({
    label: segment.charAt(0).toUpperCase() + segment.slice(1),
    to: '/' + segments.slice(0, index + 1).join('/')
  }))
})
</script>

<template>
  <UBreadcrumb :items="breadcrumbs" />
</template>

这段逻辑将 /docs/components/breadcrumb 拆解为 Docs / Components / Breadcrumb 三个层级,每一级都指向逐层累积的真实路由,用户可随时跳回任意上级页面。

UBreadcrumb 的底层细节

  • 语义化输出:根节点渲染为 <nav aria-label="breadcrumb">,内部为 <ol> 列表,最后一个 item 自动添加 aria-current="page"(见 Breadcrumb.vue);
  • RTL 感知的分隔符:默认分隔符图标为 chevronRight,但当 locale 为 RTL 方向时自动切换为 chevronLeft(Breadcrumb.vue);
  • 高可定制 item:每个 item 支持 icon、avatar、slot、class、ui 字段,可替换为任意自定义插槽内容;labelKey 默认 'label';
  • 激活样式:末级(当前页)item 使用 font-semibold + 主题色,其余层级为 text-muted(见 theme/breadcrumb.ts)。

Tab 导航:页面内部的多视图切换

当单个页面需要切换多个视图(如 Overview / Activity / Members)时,UTabs 是最直接的方案。它的核心机制是:每个 item 的 slot 字段决定对应内容区由哪个具名插槽渲染。

<script setup lang="ts">
const items = [{
  label: 'Overview',
  icon: 'i-lucide-layout-dashboard',
  slot: 'overview' as const
}, {
  label: 'Activity',
  icon: 'i-lucide-activity',
  slot: 'activity' as const
}, {
  label: 'Members',
  icon: 'i-lucide-users',
  slot: 'members' as const
}]
</script>

<template>
  <UTabs :items="items">
    <template #overview>
      <!-- Overview content -->
    </template>
    <template #activity>
      <!-- Activity feed -->
    </template>
    <template #members>
      <!-- Members list -->
    </template>
  </UTabs>
</template>

从 Tabs.vue 模板 可以看到,内容区渲染逻辑是:优先使用 item.slot 对应的具名插槽,未指定 slot 时回退到默认的 content 插槽,最终再回退到 item.content 字符串。

UTabs 关键 props 与 item 字段

项 默认值 说明
items[].label / icon / avatar / badge — Tab 触发器上的文本、图标、头像与徽标
items[].value 索引 唯一值,同时作为 Vue key,稳定的 value 可避免列表增删时内容重挂载
items[].disabled — 禁用单个 Tab
orientation 'horizontal' 水平 / 垂直排布
variant 'pill' 'pill' / 'link' 两种触发器样式
color / size 'primary' / 'md' 激活态颜色与尺寸
content true 设为 false 可禁止渲染内容区(仅保留触发器)
defaultValue / modelValue '0' 受控 / 非受控的激活值

垂直方向下,UTabs 的 type 语义与 UNavigationMenu 有微妙差异:UNavigationMenu 的 type('single' | 'multiple')控制垂直展开时可同时打开的子菜单数量,而 UTabs 单次始终只激活一个 Tab。另外,UTabs 底层基于 Reka UI 的 TabsRoot,继承其 activationMode、unmountOnHide 等行为。

组合实战:三种导航形态如何选型

需求 推荐组合 参考实现
面向公众的营销 / 博客站点 UHeader(默认插槽 + #body)+ UNavigationMenu 水平导航 landing 布局
后台管理 / 工作台 UDashboardSidebar + UNavigationMenu(orientation="vertical" + :collapsed)+ #footer 用户菜单 dashboard 布局
文档站 / 内容站 UContentNavigation(内容驱动侧边栏)+ UBreadcrumb 面包屑 UContentNavigation
单页多视图 UTabs(slot 驱动的页内导航) 本文 Tab 章节

需要特别提醒的是:UNavigationMenu 的 orientation 贯穿所有场景 —— Header 用水平(horizontal),Sidebar 用垂直(vertical)并配合折叠态,二者数据模型完全一致,这意味着同一份 items 数据可以直接复用于桌面端水平导航与移动端垂直菜单(如 Header 示例中所示),这是 Nuxt UI 导航体系最值得利用的特性之一。

登录后查看全文
ui