开篇:当按钮们决定"合体"
你有没有遇到过这种情况:页面上三个按钮一字排开,明明功能是互斥的——比如"日视图/周视图/月视图"——但它们长得像三个独立的按钮,用户选完"周视图","日视图"还亮着,仿佛在说"你可以同时选我哦"。
这就是传统按钮的痛点:它们天生是"独行侠",但现实场景中,你经常需要一组"非此即彼"的选项。
ButtonGroup(按钮组)就是来终结这种尴尬的。
它是 TinyVue 专门为"单选按钮组"场景设计的组件——不是那种圆圆的 radio,而是更直观的按钮式切换。点一个,上一个自动取消,像一群训练有素的士兵,只有一个能站出来。
1. 基础用法:三步打造一个按钮组
话不多说,先看代码:
<template>
<tiny-button-group :data="groupData" v-model="checkedVal" />
<p>当前选中值:{{ checkedVal }}</p>
</template>
<script setup>
import { ref } from 'vue'
import { TinyButtonGroup } from '@opentiny/vue'
const checkedVal = ref('Button1')
const groupData = [
{ text: 'Button1', value: 'Button1' },
{ text: 'Button2', value: 'Button2' },
{ text: 'Button3', value: 'Button3' }
]
</script>
三步到位:
- 定义数据源
data:每个按钮用{ text, value }描述,text是显示文字,value是选中值。 - 绑定
v-model:双向绑定当前选中的值,点哪个切哪个。 - 坐等收获:页面上出现三个互斥的按钮,当前选中值实时显示。
这比手动写三个按钮再自己管理选中状态优雅多了——你不需要维护一个 activeIndex,不需要在 @click 里写一堆 if-else,ButtonGroup 全帮你搞定了。
2. 尺寸三兄弟:medium / small / mini
按钮组也讲究身材管理。通过 size 属性,一个属性就能让整组按钮集体"健身":
<tiny-button-group size="medium" :data="groupData" v-model="checkedVal" />
<tiny-button-group :data="groupData" v-model="checkedVal" />
<tiny-button-group size="small" :data="groupData" v-model="checkedVal" />
<tiny-button-group size="mini" :data="groupData" v-model="checkedVal" />
三种尺寸覆盖了从"桌面端舒适点击"到"移动端紧凑布局"的全场景需求。默认不写 size 等价于 medium——省事。
小贴士:不要试图给每个按钮单独设 size,ButtonGroup 的哲学是"步调一致",整个组一个尺寸,整齐才是美。
3. 禁用状态:让某些按钮"休假"
有时候某个选项暂时不可用——比如"导出PDF"功能还在开发中,但UI上又需要展示这个选项让用户知道即将支持。
ButtonGroup 支持两个粒度的禁用:
3.1 整体禁用
<tiny-button-group :data="groupData" disabled />
此时整个按钮组灰掉,全员罢工。适合表单提交中、数据加载中这类场景。
3.2 单个按钮禁用
const groupData = [
{ text: '日视图', value: 'day' },
{ text: '周视图', value: 'week' },
{ text: '月视图', value: 'month', disabled: true, tip: '即将上线' }
]
给数据项加个 disabled: true,单个按钮就灰掉了。再加个 tip 属性(v3.17.0+),鼠标悬浮时还能弹出提示,告诉用户为什么不能用——用户体验直接拉满。
这比你自己写 :disabled + 手写 tooltip 组合拳,少了至少三行模板代码。
4. 朴素按钮:低调的另一种选择
默认的按钮组是有填充色的,视觉上比较突出。但如果你需要"低调奢华"的风格——比如在表格工具栏、卡片底部区域——用 plain 属性一键切换:
<tiny-button-group :data="groupData" v-model="checkedVal" plain />
朴素模式下,按钮只保留边框和文字颜色,背景变为透明。选中态和默认态的区分依然清晰。
5. 数据字段映射:当你的后端不按套路出牌
这是个非常实用的功能。ButtonGroup 默认认 text 和 value 这两个字段名,但现实中的接口数据可能是:
[
{ "label": "日视图", "id": "day" },
{ "label": "周视图", "id": "week" }
]
这时候不需要手动 map 转换数据,两个属性搞定:
<tiny-button-group
:data="apiData"
text-field="label"
value-field="id"
v-model="checkedVal"
/>
text-field 告诉组件从 label 字段取显示文字,value-field 告诉组件从 id 字段取选中值。省掉了循环转换的中间步骤,数据直接怼进去就行。
6. 显示更多:按钮太多?折叠它!
当一个按钮组里有七八个选项时,横向排开会很丑,甚至溢出容器。show-more 属性就是为这种情况准备的:
<tiny-button-group :data="longGroupData" :show-more="3" v-model="checkedVal" />
设置 show-more="3" 后,前面 3 个按钮正常显示,后面的统统收进"更多"按钮的下拉菜单里。点击"更多"展开,选完自动收起。
这个设计比你自己用 v-if + v-for + 下拉组件折腾方便太多了。
7. 默认插槽:当数据驱动不够用时
ButtonGroup 的数据驱动模式覆盖了 90% 的场景,但总有些时候你需要完全自定义——比如在按钮上加图标、或者按钮间的顺序和样式需要精细控制:
<tiny-button-group v-model="checkedVal">
<tiny-button value="left">← 上一步</tiny-button>
<tiny-button value="right">下一步 →</tiny-button>
</tiny-button-group>
使用默认插槽后,data、text-field、value-field、size 等属性对插槽内的按钮不再生效。你获得了完全的控制权,但也需要自己处理样式和交互。
一句话总结:数据驱动走量,插槽走心。
8. 空数据插槽:优雅地处理"啥也没有"
数据为空时,ButtonGroup 默认显示"暂无数据"。如果你觉得太生硬,可以用 empty 插槽自定义:
<tiny-button-group :data="[]">
<template #empty>
<div style="color: #999;">🏃 按钮们跑路了,请稍后再来...</div>
</template>
</tiny-button-group>
一个幽默的占位提示,比干巴巴的"暂无数据"友好多了。
9. 选块角标:按钮上的"小红点"
v3.17.0 版本新增的 sup 属性,让你能在按钮右上角加个小角标——就像微信消息的红点:
const groupData = [
{ text: '未读', value: 'unread', sup: { text: '99+' } },
{ text: '已读', value: 'read' },
{ text: '归档', value: 'archive', sup: { text: '新', class: 'custom-badge' } }
]
sup 可以配置:
text:角标文字class:自定义样式类slot:自定义插槽(用于更复杂的角标内容)icon:传入图标组件
这在消息中心、任务列表等场景非常有用——用户一眼就能看到哪个分类有待处理内容。
10. 显示模式:从"独立单间"到"豪华套房"
display-mode 属性让按钮组有两种视觉风格:
<!-- 默认模式:按钮间有间距,各自独立 -->
<tiny-button-group :data="groupData" v-model="checkedVal" />
<!-- 合并模式:按钮无缝拼接,像一个整体 -->
<tiny-button-group :data="groupData" v-model="checkedVal" display-mode="merged" />
- default(默认):按钮之间保持间距,每个按钮有独立的圆角。适合宽松布局。
- merged(合并):按钮之间无缝贴合,首尾有圆角,中间是直角。形成"分段控制器"的视觉效果,类似 iOS 的 UISegmentedControl。
11. 多行按钮组:横向撑不下了,换行继续
按钮太多但不想用"显示更多"折叠?ButtonGroup 支持自动换行:
<tiny-button-group :data="manyGroupData" v-model="checkedVal" style="max-width: 400px;" />
当容器宽度不足以容纳所有按钮时,会自动换行显示。不需要额外的配置,CSS 自动处理。
12. Change 事件:时刻掌握"谁被翻了牌子"
<tiny-button-group :data="groupData" @change="handleChange" />
<script setup>
const handleChange = (value) => {
console.log('切换到了:', value)
// 这里可以做任何事:切换视图、请求数据、更新路由...
}
</script>
每次按钮切换都会触发 change 事件,回调参数就是新选中的 value。配合 v-model 使用,数据和事件的联动天衣无缝。
总结:ButtonGroup 该不该用?
| 场景 | 是否推荐 |
|---|---|
| 互斥选项切换(日/周/月) | ✅ 强烈推荐 |
| 简单筛选(全部/已读/未读) | ✅ 强烈推荐 |
| 多个独立操作按钮 | ❌ 用单独的 <tiny-button> |
| 需要复杂自定义内容的选项 | ✅ 用插槽模式 |
| 选项超过 8 个 | ✅ 用 show-more 折叠 |
ButtonGroup 本质上是一个"单选按钮的按钮化呈现"——比 Radio 直观,比手写按钮组方便。它把"互斥选择"这个高频需求的开发成本降到了最低:
一行 data + 一行 v-model = 一个完美的按钮组。
下次你的页面上出现三个以上需要互斥的按钮时,别犹豫,ButtonGroup 就是你需要的答案。
OpenTiny NEXT 是一套企业智能前端开发解决方案,以生成式 UI 和 WebMCP 两大核心技术为基础,对现有传统的 TinyVue 组件库、TinyEngine 低代码引擎等产品进行智能化升级,构建出面向 Agent 应用的前端 NEXT-SDKs、AI Extension、TinyRobot智能助手、GenUI等新产品,实现AI理解用户意图自主完成任务,加速企业应用的智能化改造。 欢迎加入 OpenTiny 开源社区。添加微信小助手:opentiny-official 一起参与交流前端技术~
OpenTiny 官网:opentiny.design
TinyVue 代码仓库:https://https://github.com/opentiny/tiny-vue (欢迎star ⭐)