- UI组件
- 前端
【免费下载链接】varlet
A Vue3 component library based on Material Design 2 and 3, supporting mobile and desktop.
TabItem 是 Varlet(基于 Vue 3、Material Design 2/3 的组件库)中负责展示选项卡对应视图内容的面板组件,它必须与TabsItems容器配合使用,与Tabs/Tab一起构成完整的选项卡联动方案。本文将完整讲解 TabItem 的name属性与default插槽用法,并从源码层面剖析其激活匹配、滑动切换与布局实现的底层原理,帮助你写出可直接运行的选项卡视图联动代码。
组件定位:选项卡体系中的"视图面板"角色
在 Varlet 的选项卡家族中,四个组件各司其职:
Tabs:选项卡组容器,管理激活态与指示器;Tab:单个选项卡(按钮),负责被点击与高亮;TabsItems:视图容器,基于 Swipe 组件实现滑动切换;TabItem:单个视图面板,负责承载一个选项卡对应的内容。
正如 Tabs 文档 所述:"使用Tabs、Tab实现选项卡组的切换。使用TabsItems、TabItem实现和选项卡组的视图联动。" TabItem 是整个联动链条的末端,直接决定每个页面展示什么内容。从源码结构看,TabItem.vue 的模板只做了一件事——把默认插槽内容包进一个var-swipe-item:
<var-swipe-item :class="classes(n(), [!current, n('--inactive')])" var-tab-item-cover> <slot /> </var-swipe-item>也就是说,TabItem 本身不负责"切换逻辑",切换由外层TabsItems统一调度,TabItem 只负责上报自身状态(索引、名字、是否激活)并渲染内容。
API 概览:属性与插槽
TabItem 的官方 API 定义非常精简,zh-CN 文档 完整内容如下:
属性
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
name | 视图的名字 | string | number | - |
插槽
| 插槽名 | 说明 | 参数 |
|---|---|---|
default | 视图的内容 | - |
与文档对应,props.ts 中name的类型声明为[String, Number],即既可以是字符串也可以是数字;未设置时默认值为空(-)。类型声明可以在 types/tabItem.d.ts 中进一步确认:
export interface TabItemProps extends BasicAttributes { name?: string | number }default插槽没有任何作用域参数,直接书写任意模板内容即可,支持指令、组件与纯文本。
基础使用:与 TabsItems 实现视图联动
单独使用 TabItem 没有意义,它必须放置在TabsItems内部(源码中对此有强制断言,详见下文"实现原理")。下面这段来自 Tabs 文档"视图联动"示例 的代码,是 TabItem 最标准的用法——Tabs、Tab与TabsItems、TabItem共用同一个active响应式变量,点击选项卡即可切换对应视图,同时支持在视图上左右滑动切换:
<script setup> import { ref } from 'vue' const active = ref(0) </script> <template> <var-tabs elevation color="var(--color-primary)" active-color="var(--color-on-primary)" inactive-color="var(--color-on-info)" v-model:active="active" > <var-tab>选项1</var-tab> <var-tab>选项2</var-tab> <var-tab>选项3</var-tab> </var-tabs> <var-tabs-items v-model:active="active"> <var-tab-item> 呜啦啦啦火车笛,随着奔腾的马蹄。 小妹妹吹着口琴,夕阳下美了剪影。 </var-tab-item> <var-tab-item> 很多人不长眼睛,嚣张都靠武器。 赤手空拳就缩成蚂蚁。 </var-tab-item> <var-tab-item> 你们一起上,我在赶时间。 每天决斗观众都累了,英雄也累了。 </var-tab-item> </var-tabs-items> </template>也可以参考仓库内真实的 Tabs 示例页,其中通过activeRelation变量将一组Tabs与一组TabsItems绑定,并在TabItem中渲染多行文本内容。
结合 name 使用具名视图
name属性用于给视图命名,便于以稳定的标识(而不是脆弱的索引)来绑定激活状态。当active与name对应时,即使视图顺序发生调整,联动依然准确。例如:
<script setup> import { ref } from 'vue' const active = ref('overview') </script> <template> <var-tabs v-model:active="active"> <var-tab name="overview">总览</var-tab> <var-tab name="detail">详情</var-tab> </var-tabs> <var-tabs-items v-model:active="active"> <var-tab-item name="overview">总览视图内容</var-tab-item> <var-tab-item name="detail">详情视图内容</var-tab-item> </var-tabs-items> </template>name 属性的匹配机制:优先 name,其次 index
TabItem 的name到底如何参与激活匹配?答案在 TabsItems.vue 的匹配函数中:
function matchName(active: number | string | undefined): TabItemProvider | undefined { return tabItemList.find(({ name }: TabItemProvider) => active === name.value) } function matchIndex(active: number | string | undefined): TabItemProvider | undefined { return tabItemList.find(({ index }: TabItemProvider) => active === index.value) } function matchActive(active: number | string | undefined): TabItemProvider | undefined { return matchName(active) || matchIndex(active) }可以看到匹配策略是:优先按name匹配,匹配不到再回退到按index(即 TabItem 在 TabsItems 中的注册顺序)匹配。这与 Tabs 文档中"Tabs 默认通过 active 去匹配 Tab 的 index……您也可以通过给 Tab 设置 name 来命名选项卡,这时 Tabs 会优先匹配 name"的说明完全一致,只是该策略在 TabItem 侧同样生效。
当active变化时,handleActiveChange会先让所有 TabItem 失活,再激活匹配到的那一个,并驱动内部 Swipe 切换到对应位置:
tabItemList.forEach(({ setCurrent }) => setCurrent(false)) newActiveTabItemProvider.setCurrent(true) swipe.value?.to(newActiveTabItemProvider.index.value)反过来,当用户直接在视图上滑动切换时,handleSwipeChange会读取当前视图的name(优先)或index(兜底)并反向回写active:
const tabItem = tabItemList.find(({ index }) => index.value === currentIndex) as TabItemProvider const active = tabItem.name.value ?? tabItem.index.value call(props['onUpdate:active'], active)这一来一回,正是"点击选项卡切视图、滑动视图同步选项卡"双向联动的核心链路。
源码级原理解析
1. 组件实现:基于 SwipeItem 的薄封装
TabItem.vue 的setup中,组件通过useTabsItems()向父级TabsItems注册自己,并暴露一个TabItemProvider接口:
const tabItemProvider: TabItemProvider = { index, name, current: computed(() => current.value), setCurrent, } bindTabsItems(tabItemProvider) bindLists(tabItemProvider)其中current标记该视图是否激活,setCurrent由父级调用以切换激活态。同时组件还通过useLists()与List组件体系建立关联(TAB_ITEM_BIND_LIST_KEY),这是 TabItem 支持与 List 组件组合的扩展点。
2. 强制约束:必须位于 var-tabs-items 内
provide.ts 中的useTabsItems通过@varlet/use的useParent向上查找TABS_ITEMS_BIND_TAB_ITEM_KEY对应的父级 Provider,并带有明确的运行时断言:
assert(!!bindParent, 'TabItem', '<var-tab-item/> must in <var-tabs-items/>')也就是说,若将<var-tab-item>直接放到页面顶层或Tabs内部,运行时会抛出 "<var-tab-item/> must in <var-tabs-items/>" 的提示,这是组件设计上的硬性约束。
3. 样式细节:非激活视图高度归零
tabItem.less 定义了非激活视图的布局策略:
.var-tab-item { &--inactive[var-tab-item-cover] { overflow: visible; height: 0; } }当 TabItem 处于非激活状态时,通过height: 0折叠内容、overflow: visible允许内容溢出显示,从而让视图切换在视觉上表现为"内容随滑动进出",同时避免非激活视图占据布局空间。
4. 注册与类型:withInstall 插件化安装
index.ts 中组件通过withInstall与withPropsDefaultsSetter完成插件化封装,既可app.use(TabItem)全量注册,也可按需引入:
withInstall(TabItem) withPropsDefaultsSetter(TabItem, tabItemProps) export { tabItemProps } export const _TabItemComponent = TabItem export default TabItem配套组件属性:掌握 TabsItems 才能用好 TabItem
由于 TabItem 的行为完全由外层TabsItems驱动,理解TabsItems的属性才能充分发挥 TabItem 的能力。根据 TabsItems 文档 与 props.ts,其属性如下:
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
v-model:active | 激活的选项卡的名字(与 TabItem 的 name/index 对应) | string | number | 0 |
can-swipe | 是否允许在视图上滑动切换 | boolean | true |
animated | 是否启用内容切换动画 | boolean | true |
loop | 是否允许循环切换 | boolean | false |
值得注意的实现细节:animated通过控制 Swipe 的duration生效(为false时 duration 传0),can-swipe映射到 Swipe 的touchable,loop直接透传给 Swipe;此外TabsItems内部会强制隐藏 Swipe 的指示器(:indicator="false"),因为指示器语义已由上方Tabs承担。
TabsItems还暴露了getSwipe()方法,可获取内部swipe组件实例,用于需要精细控制切换的进阶场景。这一行为由仓库测试 tabs/tests/index.spec.js 验证:测试挂载TabsItems与TabItem后断言wrapper.vm.getSwipe()存在,且调用getSwipe().next()会触发onUpdate:active。同一测试文件也验证了四个组件均可通过app.use()注册。
总结与使用建议
围绕 TabItem 这枚"视图面板",可以归纳出几条可直接落地的实践要点:
- 成对使用:
TabItem只能放在TabsItems中,二者与Tabs、Tab组成四件套,共用同一个v-model:active变量实现双向联动。 - 善用 name:当视图顺序可能变化、或希望以业务语义(如路由名、数据键)驱动激活时,为 TabItem 设置
name;匹配时优先name、兜底index。 - 自由填充:
default插槽没有作用域参数,任意模板内容都可直接放入;配合can-swipe、animated、loop属性可控制手势与动画行为。 - 按需引入:TabItem 已通过
withInstall封装,支持全量注册与按需引入,类型声明见 types/tabItem.d.ts。
如果想要看到 TabItem 更多真实运行效果与组合用法,可以直接阅读仓库中的 Tabs 示例页 与 Tabs 文档,其中包含了视图联动、粘性布局、指示器反转等完整可运行示例。
- UI组件
- 前端
【免费下载链接】varlet
A Vue3 component library based on Material Design 2 and 3, supporting mobile and desktop.
相关推荐
Varlet Option 组件完全指南:属性、插槽与 Select 联动机制源码级解析
Varlet Option 组件完全指南:属性、插槽与 Select 联动机制源码级解析 Option( var option )是 Varlet 组件库中构成
UI组件前端Varlet Breadcrumb 面包屑组件完整指南:Props、事件、插槽与源码实现原理
Varlet Breadcrumb 面包屑组件完整指南:Props、事件、插槽与源码实现原理 导读 本文围绕 Vue 3 组件库 Varlet 中的 Bread
UI组件前端Varlet RailNavigationItem 单轨导航项组件完全指南:属性、事件、插槽与样式定制
Varlet RailNavigationItem 单轨导航项组件完全指南:属性、事件、插槽与样式定制 导读 RailNavigationItem 是 Varl
UI组件前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考