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
Sidebar Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| v-model | 当前激活项的值 | string | number | 0 |
SidebarItem Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| label | 选项标题 | string | - |
| value | 选项值,唯一标识;不传时使用索引 | string | number | - |
| icon | 图标 | IconName | - |
| badge-props | 徽标属性,透传给 Badge | Partial<BadgeProps> | - |
| disabled | 是否禁用当前选项 | boolean | false |
代替原始 Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| custom-id | 根节点id | string | - |
| custom-class | 根节点类名 | ClassValue | - |
| custom-style | 根节点样式 | StyleValue | - |
Sidebar Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| click | 点击时触发 | MouseEvent |
| change | 激活项切换时触发 | { value, label } |
SidebarItem Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| click | 点击时触发 | MouseEvent |
Sidebar Slots
| 名称 | 说明 |
|---|---|
| default | SidebarItem 列表 |
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 |
