Skip to content

Nav 侧边导航

分组导航。不依赖路由——选中值就是一个普通字符串。

基础用法

当前选中:/overview
vue
<script setup>
import { ref } from 'vue'

const active = ref('/overview')
const groups = [
  {
    key: 'main',
    title: '主要',
    items: [
      { value: '/overview', label: '概览' },
      { value: '/docs', label: '文档', badge: '新' }
    ]
  }
]
</script>

<template>
  <SrNav v-model="active" :groups="groups" />
</template>

为什么不依赖路由

组件的选中值就是一个普通字符串,不读 useRoute()、也不调用 router.push()。 点击时只发 update:modelValue,跳不跳、怎么跳由宿主决定。

这样做的理由:

  1. 不绑定具体路由库。Vue Router、Nuxt 的文件路由、甚至纯 hash 锚点, 都能接;
  2. 可以当纯选择器用。有些场景它就是「选一个分类」,并不需要跳转;
  3. 避免在组件库里 import vue-router——那会让不用路由的项目 也被迫装上一个 peer dependency。

接路由的写法:

vue
<script setup>
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()

const active = computed({
  get: () => route.path,
  set: (path) => router.push(path)
})
</script>

<template>
  <SrNav v-model="active" :groups="groups" />
</template>

折叠

collapsible 显示折叠按钮,collapsed 控制状态(配合 v-model:collapsed)。

折叠状态:已展开
vue
<SrNav v-model="active" v-model:collapsed="collapsed" :groups="groups" collapsible />

折叠后只显示图标,有子项时父项变为浮层入口,子项在图标右侧弹出。

折叠态需要图标

折叠后文字全部隐藏,若导航项没有图标,用户会面对一排无法区分的方块。 SrNavItem 支持 icon 插槽——需要折叠功能时务必给每项配上图标

二级菜单

children 支持一层子项。展开态下点击父项就地展开,不跳转。

vue
const groups = [
  {
    items: [
      {
        value: '/guide',
        label: '指南',
        children: [
          { value: '/guide/start', label: '快速开始' },
          { value: '/guide/theme', label: '主题定制' }
        ]
      }
    ]
  }
]

不支持无限嵌套是有意的

导航的可用性随层级急剧下降——三级以上的导航,用户既看不清当前位置, 也很难预测点击后会去哪。

超过两级应该改用 SrTree:树的展开状态一目了然,也更适合表达结构。

徽标与禁用

vue
{ value: '/docs', label: '文档', badge: '新' }     // 短文本徽标
{ value: '/changelog', label: '更新日志', badge: 3 } // 数字徽标
{ value: '/archived', label: '已归档', disabled: true }

尺寸与宽度

vue
<SrNav :groups="groups" size="sm" width="200px" collapsed-width="56px" />

Props

名称类型默认值说明
modelValuestring | number当前选中的项
groupsSrNavGroup[][]分组数据
collapsiblebooleanfalse是否显示折叠按钮
collapsedbooleanfalse是否处于折叠态
widthstring'240px'展开宽度
collapsedWidthstring'56px'折叠宽度
size'sm' | 'md''md'尺寸

数据结构

ts
interface SrNavGroup {
  key?: string          // 折叠时的分组标识,建议显式传入
  title?: string        // 分组标题,不传则不渲染标题行
  items: SrNavItem[]
}

interface SrNavItem {
  value: string | number
  label: string
  badge?: string | number
  disabled?: boolean
  children?: SrNavItem[]   // 仅支持一层
}

事件

事件参数说明
update:modelValue选中值选中项变化
update:collapsedboolean折叠状态变化

无障碍

  • <nav> 语义,并带 aria-label 说明这是什么导航
  • 当前项带 aria-current="page",读屏用户能定位自己在哪
  • 折叠按钮带 aria-expandedaria-label(「展开导航」/「收起导航」)
  • 二级菜单的父项带 aria-haspopuparia-expanded

自用组件库 · 源码分发 · 不发布 npm