资讯动态

Vant Sidebar 侧边导航组件完全指南:用法、API 与源码级原理解析

发布时间:2026/9/12 22:57:28 来源:尧图企业网站定制
Vant Sidebar 侧边导航组件完全指南用法、API 与源码级原理解析【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant导读本文围绕 Vant 4 移动端 UI 库中的Sidebar侧边导航组件展开它提供一种垂直展示的导航栏用于在不同内容区域之间快速切换常见于分类页、设置页、商品列表筛选等场景。通过本文你将掌握van-sidebar/van-sidebar-item的完整用法基础绑定、徽标、禁用、事件监听、路由跳转与自定义插槽、全部 Props / Events / Slots / CSS 变量 API并从源码与测试层面理解其父子组件通过依赖注入协同工作的底层原理最终能够独立完成样式定制与二次开发。一、组件定位与引入方式1. 组件定位Sidebar 是 Vant 中为数不多的垂直导航类组件它默认渲染一个宽度约 80px 的窄列导航项自上而下排列选中项左侧会显示一条主题色竖条适合放在页面左侧或内容区上方配合右侧内容区联动切换。官方文档将其定位概括为垂直展示的导航栏用于在不同的内容区域之间进行切换。在 Vant 的组件体系中Sidebar 由两个组件协作完成Sidebar容器负责管理选中索引状态通过v-model对外双向同步SidebarItem导航项渲染单个导航条目负责点击交互、徽标展示与路由跳转。2. 安装与全局注册组件随vant主包一起发布无需单独安装。通过app.use进行全局注册import { createApp } from vue; import { Sidebar, SidebarItem } from vant; const app createApp(); app.use(Sidebar); app.use(SidebarItem);全局注册后模板中即可直接使用van-sidebar与van-sidebar-item标签。Vant 还支持按需引入配合vant-auto-import-resolver或unplugin-vue-components、手动局部注册等多种方式更多注册方式可参考 组件注册。二、基础用法v-model 双向绑定选中项Sidebar 的核心交互就是当前选中哪一项。通过v-model绑定当前选中项的索引数字或字符串默认值为0即默认选中第一项van-sidebar v-modelactive van-sidebar-item title标签名称 / van-sidebar-item title标签名称 / van-sidebar-item title标签名称 / /van-sidebarimport { ref } from vue; export default { setup() { const active ref(0); return { active }; }, };也可以使用script setup写法script setup import { ref } from vue; const active ref(0); /script template van-sidebar v-modelactive van-sidebar-item title商品分类 / van-sidebar-item title优惠活动 / van-sidebar-item title我的订单 / /van-sidebar /template源码视角v-model 是如何工作的在 Sidebar.tsx 中Sidebar的 props 定义极其精简——只有一个modelValueexport const sidebarProps { modelValue: makeNumericProp(0), };makeNumericProp(0)表示该属性接受number | string类型默认值为0这与文档中v-model类型_number | string_、默认值0一一对应。组件通过linkChildren将两个方法注入给所有子级SidebarItemconst getActive () props.modelValue; const setActive (value: number) { if (value ! getActive()) { emit(update:modelValue, value); emit(change, value); } }; linkChildren({ getActive, setActive });关键细节getActive用一元运算符把字符串索引强制转为数字保证内部比较与高亮判断类型一致setActive只在值确实发生变化时才触发update:modelValue驱动v-model更新和change事件避免无意义的重复触发——这一点在后面的测试用例中也有印证。三、徽标提示dot 与 badgeSidebarItem 内置了 Badge 徽标能力支持两种展示形式dot在标题右上角展示一个小红点布尔值默认falsebadge在标题右上角展示徽标内容number | string支持数字角标或自定义文本。van-sidebar v-modelactive van-sidebar-item title标签名称 dot / van-sidebar-item title标签名称 badge5 / van-sidebar-item title标签名称 / /van-sidebar进阶badge-props 透传 Badge 属性如果默认徽标样式不够用可以通过badge-props把任意 Badge 组件 的属性透传进去例如自定义徽标颜色van-sidebar v-modelactive van-sidebar-item title消息 :badge99 :badge-props{ color: #1989fa } / van-sidebar-item title任务 dot / /van-sidebar源码视角徽标如何渲染在 SidebarItem.tsx 中标题被包裹在Badge组件内部Badge dot{dot} class{bem(text)} content{badge} {...props.badgeProps} {slots.title ? slots.title() : title} /Badge可以看到badge-props通过展开运算符{...props.badgeProps}直接透传给 Badge。测试文件 index.spec.tsx 中专门验证了这条链路test(should render badge-props correctly, () { // ... SidebarItem badge{1} badgeProps{{ color: blue }} / // ... expect(badge.style.backgroundColor).toEqual(blue); });即badgeProps{{ color: blue }}会真实作用到渲染出的.van-badge元素的背景色上。四、禁用选项通过disabled属性可以禁用某个导航项。被禁用的项点击无响应、不会触发切换样式上会使用禁用态颜色并将鼠标光标变为not-allowedvan-sidebar v-modelactive van-sidebar-item title标签名称 / van-sidebar-item title标签名称 disabled / van-sidebar-item title标签名称 / /van-sidebar源码视角禁用如何拦截点击SidebarItem 的点击处理逻辑非常直接const onClick () { if (props.disabled) { return; } emit(click, index.value); parent.setActive(index.value); route(); };disabled时直接return既不会触发click事件也不会调用parent.setActive更新选中状态。测试用例 index.spec.tsx 也验证了这一点test(should not update v-model when disabled SidebarItem is clicked, () { // 点击 index1 的 disabled 项后 expect(wrapper.vm.active).toEqual(0); // v-model 保持 0 不变 });五、监听切换事件change 与 clickSidebar 提供两个与交互相关的事件changeSidebar 级别选中项变化时触发回调参数为选中项索引index: numberclickSidebarItem 级别点击某个导航项时触发回调参数同样为该索引。van-sidebar v-modelactive changeonChange van-sidebar-item title标签名 1 / van-sidebar-item title标签名 2 / van-sidebar-item title标签名 3 / /van-sidebarimport { ref } from vue; import { showToast } from vant; export default { setup() { const active ref(0); const onChange (index) showToast(标签名 ${index 1}); return { active, onChange, }; }, };源码视角两个事件的分工与触发时机从上面的onClick源码可以看出触发顺序为先emit(click, index.value)SidebarItem 的 click再parent.setActive(index.value)其内部再触发 Sidebar 的change。也就是说一次点击会依次触发click事件和change事件但change仅在选中索引真正改变时触发setActive内部有value ! getActive()判断。测试用例对这套行为做了精确断言test(should emit change event when active item changed, () { // 点击第 0 项因已是选中项change 不触发 expect(onChange).toHaveBeenCalledTimes(0); // 点击第 1 项change 触发且参数为 1 items[1].trigger(click); expect(onChange).toHaveBeenCalledWith(1); }); test(should emit click event when SidebarItem is clicked, () { wrapper.find(.van-sidebar-item).trigger(click); expect(onClick).toHaveBeenCalledWith(0); // 点击事件始终触发未禁用时 });实践中两者的选型建议需要联动内容区刷新时监听 Sidebar 的change需要统计点击行为/处理单项特例时监听 SidebarItem 的click。六、标题插槽与路由跳转1. title 插槽自定义内容如果标题不只是纯文本例如要嵌入图标、富文本或模板片段可以使用title插槽完全接管标题渲染van-sidebar v-modelactive van-sidebar-item template #title van-icon namewap-home-o / 首页 /template /van-sidebar-item van-sidebar-item title分类 / /van-sidebar使用插槽时title属性会被忽略源码中slots.title ? slots.title() : title的优先级顺序即为此意。测试 index.spec.tsx 中也有对应快照用例。2. 路由与链接跳转SidebarItem 继承了 Vant 统一的routeProps定义见 use-route.ts支持三种跳转方式属性类型说明urlstring点击后跳转的链接地址原生跳转tostring \| object跳转的目标路由等同于 Vue Router 的to属性replaceboolean是否在跳转时替换当前页面历史记录默认falsevan-sidebar v-modelactive van-sidebar-item title关于我们 urlhttps://example.com/about / van-sidebar-item title个人中心 :to{ name: user } / van-sidebar-item title设置 to/settings replace / /van-sidebar其底层实现在点击时调用route()export function route({ to, url, replace, $router: router }) { if (to router) { routerreplace ? replace : push; } else if (url) { replace ? location.replace(url) : (location.href url); } }可见跳转优先级为to需要应用已注册 Vue Router优先于url原生页面跳转replacetrue时分别对应router.replace与location.replace不会在历史栈中留下记录。七、完整 API 参考Sidebar Props参数说明类型默认值v-model当前导航项的索引number \| string0Sidebar Events事件名说明回调参数change切换导航项时触发index: numberSidebarItem Props参数说明类型默认值title内容stringdot是否显示右上角小红点booleanfalsebadge图标右上角徽标的内容number \| string-badge-props自定义徽标的属性透传给 Badge 组件的 propsBadgeProps-disabled是否禁用该项booleanfalseurl点击后跳转的链接地址string-to点击后跳转的目标路由对象等同于 Vue Router 的to属性string \| object-replace是否在跳转时替换当前页面历史booleanfalseSidebarItem Events事件名说明回调参数click点击时触发index: numberSidebarItem Slots名称说明title自定义标题类型定义组件导出以下 TypeScript 类型便于在业务代码中获得完整的类型提示import type { SidebarProps, SidebarItemProps } from vant;同时 Vant 还导出了样式变量类型SidebarThemeVars/SidebarItemThemeVars见 sidebar/types.ts 与 sidebar-item/types.ts配合 ConfigProvider 的theme-vars使用时可获得键名校验。八、主题定制CSS 变量全解析Sidebar 系列组件提供了 13 个 CSS 变量用于样式定制所有变量均在 sidebar-item/index.less 的:root/:host中声明--van-sidebar-width声明于 sidebar/index.less默认值引用了 Vant 全局设计变量保证视觉体系一致名称默认值作用--van-sidebar-width80px侧边导航整体宽度--van-sidebar-font-sizevar(--van-font-size-md)导航项文字大小--van-sidebar-line-heightvar(--van-line-height-md)导航项行高--van-sidebar-text-colorvar(--van-text-color)导航项文字颜色--van-sidebar-disabled-text-colorvar(--van-text-color-3)禁用态文字颜色--van-sidebar-padding20px var(--van-padding-sm)导航项内边距--van-sidebar-active-colorvar(--van-active-color)按压active态背景色--van-sidebar-backgroundvar(--van-background)导航项背景色--van-sidebar-selected-font-weightvar(--van-font-bold)选中项字重--van-sidebar-selected-text-colorvar(--van-text-color)选中项文字颜色--van-sidebar-selected-border-width4px选中态左侧竖条宽度--van-sidebar-selected-border-height16px选中态左侧竖条高度--van-sidebar-selected-border-colorvar(--van-primary-color)选中态左侧竖条颜色--van-sidebar-selected-backgroundvar(--van-background-2)选中项背景色两种定制方式方式一CSS 覆盖最简单直接覆盖同名变量.van-sidebar { --van-sidebar-width: 96px; --van-sidebar-selected-border-color: #ff976a; }方式二通过 ConfigProvider 全局定制主题化方案变量会作用于子树内所有组件参见 ConfigProvider 组件van-config-provider :theme-varsthemeVars van-sidebar v-modelactive van-sidebar-item title标签名称 / /van-sidebar /van-config-providerimport { ref } from vue; export default { setup() { const active ref(0); const themeVars { sidebarWidth: 100px, sidebarSelectedBorderColor: #ee0a24, }; return { active, themeVars }; }, };需要说明的是选中态左侧竖条通过--select::before伪元素实现绝对定位于左侧、垂直居中宽高分别由--van-sidebar-selected-border-width/--van-sidebar-selected-border-height控制因此调整竖条粗细时只需修改这两个变量即可。九、源码级联动原理provide / inject 协作模型理解 Sidebar 的内部机制关键在两点父组件如何管理状态、子组件如何感知父组件。1. 父子通信链路在 Sidebar.tsx 中Sidebar通过vant/use的useChildren向所有子级注入getActive/setActiveexport type SidebarProvide { getActive: () number; setActive: (value: number) void; }; export const SIDEBAR_KEY: InjectionKeySidebarProvide Symbol(name); // Sidebar setup 内 const { linkChildren } useChildren(SIDEBAR_KEY); linkChildren({ getActive, setActive });在 SidebarItem.tsx 中子组件通过useParent(SIDEBAR_KEY)反向获取父级实例与自身索引const { parent, index } useParent(SIDEBAR_KEY); if (!parent) { if (process.env.NODE_ENV ! production) { console.error([Vant] SidebarItem must be a child component of Sidebar.); } return; }注意这段健壮性处理当SidebarItem被错误地放置在Sidebar之外时开发环境会输出明确的错误提示避免静默失效。2. 选中态与无障碍语义选中判断const selected index.value parent.getActive();——由子组件自行比对索引并添加van-sidebar-item--select类无障碍Sidebar根节点带roletablist每个SidebarItem带roletab、aria-selected当前选中态与tabindex禁用时移除焦点能力天然符合 ARIA 标签页Tabs语义方便读屏软件识别。3. 滚动与文本细节容器样式sidebar/index.less设置了overflow-y: auto与-webkit-overflow-scrolling: touch导航项较多时容器内部可独立滚动标题文本.van-sidebar-item__text设置了word-break: break-all对应 Vant issue #7455避免超长标题撑破布局导航项之间通过:not(:last-child)::after绘制 1px 分隔线利用 Vant 全局 hairline 机制。十、从 Demo 与测试看真实应用1. 官方 Demo 的结构官方演示页面 demo/index.vue 用van-grid将四个场景基础用法 / 徽标提示 / 禁用选项 / 监听切换事件并排展示并配合showToast演示 change 回调是快速上手组件形态的最佳参考。2. 测试用例覆盖的行为契约sidebar/test/index.spec.tsx 覆盖了组件的核心契约可作为业务开发的行为文档点击当前已选中项不触发change去重逻辑切换选中项触发change且参数为正确索引点击非禁用项触发clickv-model随点击正确更新且change只触发一次点击disabled项不更新v-modeltitle插槽与badge-props透传均正常渲染。结语Sidebar 是 Vant 组件库中小而精的典型外部 API 仅有v-model与少量 Props内部却依托useChildren/useParent的依赖注入模型、Badge 组件复用与统一的路由封装useRoute实现了完整且健壮的导航交互。掌握其用法与原理后无论是快速接入5 分钟即可落地一个可用的侧边导航、深度定制CSS 变量 ConfigProvider 主题还是二次扩展新增插槽、路由联动都有清晰的实现路径可循。相关文件索引组件实现Sidebar.tsx、SidebarItem.tsx类型定义sidebar/types.ts、sidebar-item/types.ts样式sidebar/index.less、sidebar-item/index.less测试sidebar/test/index.spec.tsx演示sidebar/demo/index.vue【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价