Skip to content

Sidebar 侧边导航 ​

介绍 ​

垂直展示的导航栏,常用于筛选分类,支持与滚动内容联动的锚点切换。

基础用法 ​

通过 v-model 绑定当前选中项的值。

html
<vd-sidebar v-model="active">
  <vd-sidebar-item :value="0" label="标签名称" />
  <vd-sidebar-item :value="1" label="标签名称" />
  <vd-sidebar-item :value="2" label="标签名称" />
</vd-sidebar>
ts
const active = ref(0);

徽标提示 ​

通过 badge-props 透传给 Badge(如 dot、value、max)。

html
<vd-sidebar v-model="active">
  <vd-sidebar-item :value="0" label="标签名称" :badge-props="{ dot: true }" />
  <vd-sidebar-item :value="1" label="标签名称" :badge-props="{ value: 5 }" />
  <vd-sidebar-item
    :value="2"
    label="标签名称"
    :badge-props="{ value: 55, max: 99 }"
  />
</vd-sidebar>
ts
const active = ref(0);

禁用选项 ​

通过 disabled 禁用选项。若需异步确认后再切换,可自行控制 v-model,并在业务侧展示 loading。

html
<vd-sidebar v-model="active">
  <vd-sidebar-item :value="0" label="标签名称" />
  <vd-sidebar-item :value="1" label="标签名称" disabled />
  <vd-sidebar-item :value="2" label="标签名称" />
</vd-sidebar>
ts
const active = ref(0);

自定义图标 ​

通过 icon 属性或 icon 插槽自定义图标。

html
<vd-sidebar v-model="active">
  <vd-sidebar-item :value="0" label="首页" icon="home" />
  <vd-sidebar-item :value="1" label="消息" icon="msg" />
  <vd-sidebar-item :value="2" label="我的" icon="user" />
</vd-sidebar>
ts
const active = ref(0);

锚点用法 ​

推荐配合 vd-scroller:点击侧边项用 scrollToView 跳转到对应区块;滚动时根据段落偏移反向同步激活项。内容尺寸变化时监听 @updated 重新测量偏移。

html
<view class="sidebar-anchor">
  <vd-sidebar v-model="active" @change="handleChange">
    <vd-sidebar-item
      v-for="(item, index) in categories"
      :key="index"
      :value="index"
      :label="item.label"
    />
  </vd-sidebar>

  <vd-scroller
    ref="scrollerRef"
    custom-class="sidebar-anchor__content"
    scroll-y
    @scroll="onScroll"
    @updated="refreshOffsets"
  >
    <view
      v-for="(item, index) in categories"
      :id="`category-${index}`"
      :key="index"
      class="sidebar-anchor__category"
    >
      <view class="sidebar-anchor__title">{{ item.title }}</view>
      <view
        v-for="(cell, cellIndex) in item.items"
        :key="cellIndex"
        class="sidebar-anchor__cell"
      >{{ cell }}</view>
    </view>
  </vd-scroller>
</view>
ts
import { useSelectorQuery } from '@vital-design/use';
import type { ScrollerOnScrollEvent, SidebarChangeEvent } from 'vital-design';

const active = ref(0);
const scrollerRef = shallowRef();
const instance = getCurrentInstance();
const { getSelectorRects } = useSelectorQuery();

const itemScrollTop = ref<number[]>([]);
const locking = ref(false);

const categories = [
  { label: '分类一', title: '标题一', items: Array(8).fill('内容') },
  { label: '分类二', title: '标题二', items: Array(8).fill('内容') },
  { label: '分类三', title: '标题三', items: Array(8).fill('内容') },
];

async function refreshOffsets() {
  try {
    const list = await getSelectorRects('.sidebar-anchor__category');
    const base = list[0]?.top || 0;
    itemScrollTop.value = list.map((item) => (item.top || 0) - base);
  } catch {}
}

async function handleChange({ value }: SidebarChangeEvent) {
  locking.value = true;

  try {
    await scrollerRef.value?.scrollToView({
      selector: `#category-${value}`,
      instance,
      direction: ['y'],
    });
  } finally {
    locking.value = false;
  }
}

function onScroll(data: ScrollerOnScrollEvent) {
  if (locking.value) return;

  const top = data.scrollTop;
  const threshold = 50;

  if (top < threshold) {
    active.value = 0;
    return;
  }

  let current = 0;
  for (let i = 0; i < itemScrollTop.value.length; i++) {
    if (itemScrollTop.value[i] - threshold <= top) {
      current = i;
    }
  }
  active.value = current;
}
scss
.sidebar-anchor {
  display: flex;
  height: 60vh;

  &__content {
    flex: 1;
    height: 100%;
    background: #fff;
  }

  &__title {
    margin-bottom: 8px;
    font-weight: bold;
  }

  &__cell {
    padding: 12px 0;
    border-bottom: 1px solid #eee;
  }
}

API ​

参数说明类型默认值
v-model当前激活项的值string | number0

SidebarItem Props ​

参数说明类型默认值
label选项标题string-
value选项值,唯一标识;不传时使用索引string | number-
icon图标IconName-
badge-props徽标属性,透传给 BadgePartial<BadgeProps>-
disabled是否禁用当前选项booleanfalse

代替原始 Props ​

参数说明类型默认值
custom-id根节点idstring-
custom-class根节点类名ClassValue-
custom-style根节点样式StyleValue-
事件名说明回调参数
click点击时触发MouseEvent
change激活项切换时触发{ value, label }

SidebarItem Events ​

事件名说明回调参数
click点击时触发MouseEvent
名称说明
defaultSidebarItem 列表

SidebarItem Slots ​

名称说明
default自定义标题内容
icon自定义图标内容

主题变量 ​

通过 ConfigProvider 的 theme-vars.sidebar / theme-vars.sidebar-item 覆盖:

Sidebar

名称说明默认值
width侧栏宽度90px
height侧栏高度100%

SidebarItem

名称说明默认值
font-size字号$vd-font-size-md
line-height行高$vd-line-height-md
color文字颜色$vd-color-text
padding内边距$vd-padding-xs $vd-padding-sm
background背景色$vd-background-2
min-height最小高度48px
active-background激活项背景色$vd-background
active-color激活项文字 / 指示条颜色$vd-primary
active-font-weight激活项字重bold
indicator-width激活指示条宽度3px
indicator-height激活指示条高度16px
disabled-color禁用项文字颜色$vd-color-text-3
icon-size图标字号$vd-font-size-xl
icon-gap图标与文字间距$vd-gap-xs

赣ICP备2025061025号-1