更新记录
1.3.2(2026-10-13)
下载此版本
- 修复开启横向滚动(
swipe-threshold)后标签「竖着排」的缺陷:H5 下 scroll-view 会在自身与插槽之间插入 display: block 的 .uni-scroll-view-content,此前把承载层(display: flex + tab flex: none)直接放在 scroll-view 上,tab 实际落进块级容器里逐个换行堆叠,scroll-x 完全失效。
- 改为:
scroll-view 自身只负责宽度与 white-space: nowrap(新类 .vant-tabs__nav-scroll),滚动内容交由新增的内层 .vant-tabs__nav-wrap--scrollable 承载,并改用 display: inline-flex(行内级,宽度收缩到内容宽度),tab 才能横向排列并溢出触发滚动;scroll-into-view 对激活项的自动滚动同步恢复。
- 该结构同时兼容小程序端:
scroll-view 的直接子节点即承载层,不再依赖 enable-flex。
- 演示页面同步调整:
swipe-threshold 示例改用长标签名,使溢出与自动滚动可见(此前 8 个短标签总宽未超出容器,看不出滚动效果)。
平台兼容性
uni-app(3.8.5)
| Vue2 |
Vue3 |
Chrome |
Safari |
app-vue |
app-nvue |
Android |
iOS |
鸿蒙 |
| - |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
| 微信小程序 |
支付宝小程序 |
抖音小程序 |
百度小程序 |
快手小程序 |
京东小程序 |
鸿蒙元服务 |
QQ小程序 |
飞书小程序 |
小红书小程序 |
快应用-华为 |
快应用-联盟 |
| √ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
uni-app x(3.8.5)
| Chrome |
Safari |
Android |
iOS |
鸿蒙 |
微信小程序 |
| - |
- |
- |
- |
- |
- |
其他
| 多语言 |
暗黑模式 |
宽屏模式 |
蒸汽模式 |
| × |
× |
√ |
× |
vant-tabs 标签页
标签页组件,由父组件 vant-tabs 与子组件 vant-tab 组合使用。支持 line / card 两种类型、滑动下划线、粘性定位与左右滑动切换;纯数据驱动 + 事件外抛,零业务耦合。
引入
<vant-tabs /> 与 <vant-tab /> 经 easycom 自动注册,无需 import。
代码演示
基础用法(line 类型)
<template>
<vant-tabs v-model="active">
<vant-tab title="标签一">内容一</vant-tab>
<vant-tab title="标签二">内容二</vant-tab>
<vant-tab title="标签三" disabled>内容三(禁用)</vant-tab>
</vant-tabs>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const active = ref(0)
</script>
card 类型
<vant-tabs v-model="active" type="card" active-color="#ee0a24">
<vant-tab title="首页">首页内容</vant-tab>
<vant-tab title="分类">分类内容</vant-tab>
</vant-tabs>
指定 name(非索引值)
<vant-tabs v-model="activeName">
<vant-tab title="A" name="a">AAA</vant-tab>
<vant-tab title="B" name="b">BBB</vant-tab>
</vant-tabs>
横向滚动(多标签)
标签数量超过 swipe-threshold(默认 5)时,导航栏自动开启横向滚动,标签不再被压缩。支持 v-for 批量生成标签:
<vant-tabs v-model="active" :swipe-threshold="4">
<vant-tab v-for="i in 10" :key="i" :title="`标签${i}`">内容{{ i }}</vant-tab>
</vant-tabs>
切换前拦截(before-change)
点击/滑动切换前执行 before-change,返回 false 或 reject 可阻止本次切换,适合未保存校验:
<vant-tabs v-model="active" :before-change="onBeforeChange">
<vant-tab title="表单" name="form">表单内容(未保存禁止离开)</vant-tab>
<vant-tab title="列表" name="list">列表内容</vant-tab>
</vant-tabs>
const onBeforeChange = (name: string | number) => {
if (name === 'list' && hasUnsaved.value) {
uni.showModal({ title: '提示', content: '有未保存内容,确定离开?' })
return false // 或 return Promise<boolean>
}
return true
}
标题配色分离(title-active-color / title-inactive-color)
选中 / 未选中标签文字颜色可独立控制,优先于 activeColor / color,且不影响下划线颜色:
<vant-tabs
v-model="active"
active-color="#ee0a24"
title-active-color="#ee0a24"
title-inactive-color="#969799"
>
<vant-tab title="首页">首页内容</vant-tab>
<vant-tab title="分类">分类内容</vant-tab>
</vant-tabs>
徽标 / 红点
<vant-tabs v-model="active">
<vant-tab title="消息" dot>消息列表</vant-tab>
<vant-tab title="订单" badge="5">订单列表</vant-tab>
<vant-tab title="购物车" badge="99+">购物车</vant-tab>
</vant-tabs>
自定义标题(title 插槽)
<vant-tabs v-model="active">
<vant-tab title="默认标题">内容</vant-tab>
<vant-tab>
<template #title>
<text style="margin-right: 4rpx">🔥</text>热门
</template>
热门内容
</vant-tab>
</vant-tabs>
API
vant-tabs Props
| 参数 |
说明 |
类型 |
默认值 |
| modelValue |
当前选中项标识(v-model,默认取下标,name 后匹配 name) |
number | string |
0 |
| type |
类型 |
'line' | 'card' |
'line' |
| lineWidth |
下划线宽度(line 类型,rpx) |
string | number |
40 |
| lineHeight |
下划线高度(line 类型,rpx) |
string | number |
6 |
| sticky |
是否粘性定位(仅导航栏吸顶,内容正常滚动) |
boolean |
false |
| offsetTop |
吸顶时与顶部距离;数字按 px,字符串原样透传(如 '88rpx') |
string | number |
0 |
| animated |
切换内容是否启用过渡 |
boolean |
true |
| color |
文字颜色(覆盖主题色) |
string |
'' |
| activeColor |
选中态主色(覆盖主题色,作用于下划线与选中标签) |
string |
'' |
| background |
导航栏背景色(仅作用于标签栏,不影响内容区) |
string |
'' |
| border |
是否显示底部分割线 |
boolean |
true |
| ellipsis |
标题过长是否省略 |
boolean |
true |
| swipeable |
是否支持左右滑动切换 |
boolean |
false |
| swipeThreshold |
标签数量超过该阈值开启导航栏横向滚动(0 始终滚动,-1 始终不滚动) |
number |
5 |
| beforeChange |
切换前拦截:返回 false 或 reject 的 Promise 则阻止本次切换(常用于未保存校验);回调入参为待切换项的 name |
(name: number | string) => boolean | Promise |
undefined |
| titleActiveColor |
选中标签文字颜色(优先于 activeColor,仅作用于标题文字,不影响下划线) |
string |
'' |
| titleInactiveColor |
未选中标签文字颜色(优先于 color,仅作用于标题文字) |
string |
'' |
vant-tab Props
| 参数 |
说明 |
类型 |
默认值 |
| title |
标签页标题(纯文本) |
string |
'' |
| name |
标识值(替代下标) |
string | number |
'' |
| disabled |
是否禁用该标签 |
boolean |
false |
| dot |
是否显示右上角小红点(与 badge 互斥,优先) |
boolean |
false |
| badge |
徽标内容;空字符串 '' 不显示;数字/文本显示 |
string | number |
'' |
Events
| 事件名 |
说明 |
回调参数 |
| update:modelValue |
选中项变化 |
(name: number | string) |
| change |
选中项变化(仅当激活项真正改变时触发) |
(name: number | string) |
| scroll |
滚动时触发,仅 sticky 模式下生效(H5) |
({ scrollTop: number, isFixed: boolean }) |
| click(vant-tab) |
点击标签内容 |
无 |
Slots
| 名称 |
说明 |
| default |
vant-tabs 内放置若干 <vant-tab>;vant-tab 的 default 为对应面板内容 |
| title(vant-tab) |
vant-tab 的 title 插槽自定义导航栏标题内容(图标+文字等),优先级高于 title 属性 |
主题定制
- 文字色默认取
$uni-text-color,选中态取 $uni-color-primary,均可通过 color / activeColor 覆盖。
- 导航栏背景默认取
$uni-bg-color,可通过 background 覆盖(仅作用于标签栏,内容区保持页面底色)。
常见问题
- Q:禁用标签还能点吗?
A:不能。
disabled 的 vant-tab 在导航栏不可点击,也不参与切换。
- Q:内容区如何只渲染当前项?
A:父组件通过
useSlots() 读取子节点元数据,仅渲染当前激活项的 default 插槽内容,零额外 DOM。
- Q:sticky 下内容不跟着滚?
A:吸顶只固定导航栏(
position: sticky 作用于 .vant-tabs__nav),内容区随页面正常滚动;若页面顶部另有自定义导航栏,用 offset-top 留出距离。