amis 按钮点选控件 button-group-select:用 JSON 配置实现按钮式表单选择器
【免费下载链接】amis前端低代码框架,通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis
在 amis 低代码框架中,button-group-select是一种"按钮集合当 select 点选"的表单项控件:它以按钮组的视觉形态呈现一组选项,用户点击按钮即完成选择,适合作为性别、状态、类型等少量枚举值的快速选择器。本文基于官方文档 button-group-select 组件文档 与仓库源码,完整讲解其基本用法、垂直/平铺布局、按钮主题样式、角标配置、选项与值格式化参数,以及change事件与clear/reset/reload/setValue四类特性动作,并结合 组件实现文件 与 选项控件 HOC 说明其底层调用链。读完后你可以直接用 JSON Schema 搭建按钮点选表单项,并掌握与数据域联动、跨组件控制的完整方案。
基本用法
在form的body中放置一个type: "button-group-select"的表单项,通过options声明选项集合,即可得到一个可点选的按钮组。选中值会写入表单数据域的name字段(本例为type),随表单提交到api指定的接口:
{ "type": "form", "api": "/api/mock2/form/saveForm", "debug": true, "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "options": [ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c"} ] } ] }从源码看,该控件的渲染器注册在 ButtonGroupSelect.tsx,使用@OptionsControl装饰器以type: 'button-group-select'注册,并声明了sizeMutable: false(尺寸不可被表单联动改变)与strictMode: false(不启用严格更新模式,选项/数据变化时允许重渲染)。组件本体继承自OptionsControlProps,即所有"列表选择类控件"(Select、Radios、Checkboxes 等)共用的父类接口,因此它天然获得选项加载、多选、值格式化等一整套能力。
垂直模式
配置"vertical": true后,按钮组由横向排列改为纵向排列,适合选项文字较长、标签较多、需要逐行点选的场景:
{ "type": "form", "api": "/api/mock2/form/saveForm", "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "vertical": true, "options": [ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c"} ] } ] }实现上,render方法会把vertical转成根节点样式类ButtonGroup--vertical(见 ButtonGroupSelect.tsx 的 render),对应样式定义在 amis-ui 按钮组 SCSS 中;对应的单元测试 buttonGroupSelect.test.tsx 通过断言.cxd-ButtonGroup.cxd-ButtonGroup--vertical存在来验证该行为。
平铺模式
配置"tiled": true实现平铺模式,按钮按网格均匀铺满容器宽度,视觉上更接近"卡片点选",适合移动端或需要大点击热区的场景:
{ "type": "form", "api": "/api/mock2/form/saveForm", "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "tiled": true, "options": [ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c"} ] } ] }与垂直模式同理,tiled会映射到样式类ButtonGroup--tiled(SCSS 中的平铺样式),单元测试中同样以.cxd-ButtonGroup--tiled的存在性作为验证依据(测试代码)。
按钮主题样式:btnLevel 与 btnActiveLevel
配置btnLevel统一设置所有按钮的主题样式,配置btnActiveLevel为按钮设置激活态(选中态)的主题样式。注意:buttons或options中每个选项自己的level属性优先级高于btnLevel:
{ "type": "form", "api": "/api/mock2/form/saveForm", "debug": true, "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "btnLevel": "light", "btnActiveLevel": "warning", "options": [ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c", "level": "primary"} ] } ] }btnLevel与btnActiveLevel的取值范围为'link' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger' | 'light' | 'dark' | 'default',文档标注的默认值均为"default"。
源码中的优先级逻辑非常直白,选中按钮的 level 按"激活样式 > 选项自身样式 > 整体默认样式"计算(level 计算表达式):
level: (active ? btnActiveLevel : '') || option.level || btnLevel即:按钮处于选中态时优先使用btnActiveLevel;未选中时先取选项自己的level,再回退到btnLevel。另外,若配置了旧版属性btnClassName/btnActiveClassName,源码会通过getLevelFromClassName解析出 level 覆盖btnLevel/btnActiveLevel(className 解析逻辑),这两个旧属性在新版中已被标记为废弃。组件类型定义 中也明确注释了@deprecated 建议用btnLevel。
单测 btnActiveLevel 用例 精确验证了这套优先级:在btnLevel: 'light'、btnActiveLevel: 'warning'的配置下,选中项(value: 'a')最终呈现cxd-Button--warning,未选中但带level: 'primary'的项呈现cxd-Button--primary,其余项回退为cxd-Button--light。
支持角标
按钮可支持角标,在options的单个选项中配置badge即可。badge支持mode: "text"(数字/文字角标)与mode: "ribbon"(缎带角标)等形态,完整属性见 badge 组件文档:
{ "type": "form", "api": "/api/mock2/form/saveForm", "debug": true, "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "options": [ {"label": "Option A", "value": "a"}, { "label": "Option B", "value": "b", "badge": {"mode": "text", "text": 15} }, { "label": "Option C", "value": "c", "badge": {"mode": "ribbon", "text": "HOT"} } ] } ] }从源码看,角标配置还具备"控件级兜底 + 选项级覆盖"的合并能力(getBadgeConfig 方法):如果控件整体配置了badge,则每个选项的badge(对象会展开覆盖兜底配置,字符串/数字会填充到text字段)优先生效;未配置控件级badge时直接使用选项自身配置。该能力自2.8.1版本引入。
属性表
当做选择器表单项使用时,除了支持 普通表单项属性表 中的配置以外,还支持下面一些配置:
| 属性名 | 类型 | 默认值 | 说明 | 版本 |
|---|---|---|---|---|
| type | string | "button-group-select" | 指定为 button-group-select 渲染器 | |
| vertical | boolean | false | 是否使用垂直模式 | |
| tiled | boolean | false | 是否使用平铺模式 | |
| btnLevel | 'link' \| 'primary' \| 'secondary' \| 'info' \| 'success' \| 'warning' \| 'danger' \| 'light' \| 'dark' \| 'default' | "default" | 按钮样式 | |
| btnActiveLevel | 'link' \| 'primary' \| 'secondary' \| 'info' \| 'success' \| 'warning' \| 'danger' \| 'light' \| 'dark' \| 'default' | "default" | 选中按钮样式 | |
| options | Array<object>或Array<string> | 静态选项组 | ||
| option.badge | object | 角标 | 2.8.1 | |
| source | string或 API | 动态选项组 | ||
| multiple | boolean | false | 多选 | |
| labelField | string | "label" | 选项标签字段 | |
| valueField | string | "value" | 选项值字段 | |
| joinValues | boolean | true | 拼接值 | |
| extractValue | boolean | false | 提取值 | |
| autoFill | object | 自动填充 |
补充几点与源码互相印证的细节:
source支持字符串 URL、API 对象,也支持形如"${xxx}"的纯变量表达式从数据域取选项;labelField/valueField用于指定选项中"标签"和"值"的字段名(源码渲染按钮文本时即为option[labelField || 'label'],见 渲染逻辑)。- 多选模式下的值格式化由
joinValues(默认true,用delimiter把多个值拼成字符串)与extractValue(默认false,开启后值封装为数组)共同决定,实现位于 OptionsControlBase 的 formatValueArray / toggleValue 中。单选模式下clearable(该控件默认false,见 defaultProps)允许再次点击已选按钮取消选择。 - 若
options与buttons均为空,控件会渲染占位文本(placeholder 分支),配合placeholder属性显示提示文案。
事件表
当前组件会对外派发以下事件,可以通过onEvent来监听这些事件,并通过actions来配置执行的动作,在actions中可以通过${事件参数名}或${event.data.[事件参数名]}来获取事件产生的数据,详细请查看 事件动作。
[name]表示当前组件绑定的名称,即name属性,如果没有配置name属性,则通过value取值。
| 事件名称 | 事件参数 | 说明 |
|---|---|---|
| change | [name]: string组件的值 | 选中值变化时触发 |
从源码调用链看,按钮点击触发handleToggle→ 父层 OptionsControlBase.handleToggle 计算新值后,先dispatchOptionEvent('change', {value: newValue})派发change事件(支持在 actions 中返回prevented阻塞取值),未被阻塞才调用onChange写回表单值。也就是说,change事件可以在其他组件的联动动作中被拦截。
change
{ "type": "form", "debug": true, "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "options": [ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c"} ], "onEvent": { "change": { "actions": [ { "actionType": "toast", "args": { "msg": "${event.data.value|json}" } } ] } } } ] }动作表
当前组件对外暴露以下特性动作,其他组件可以通过指定actionType: 动作名称、componentId: 该组件id来触发这些动作,动作配置可以通过args: {动作配置项名称: xxx}来配置具体的参数,详细请查看 事件动作。
| 动作名称 | 动作配置 | 说明 |
|---|---|---|
| clear | - | 清空 |
| reset | - | 将值重置为初始值。6.3.0 及以下版本为resetValue |
| reload | - | 重新加载,调用source,刷新数据域数据刷新(重新加载) |
| setValue | value: string更新的值 | 更新数据 |
其中clear与reset的具体实现在 ButtonGroupControl.doAction 中:clear直接调用onChange('')清空;reset则优先取表单初始值(formStore.pristine)中该name对应的值,取不到再回退到resetValue,最后兜底为空字符串。
clear
{ "type": "form", "debug": true, "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "id": "clear_type", "options": [ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c"} ], "value": "b" }, { "type": "button", "label": "清空", "onEvent": { "click": { "actions": [ { "actionType": "clear", "componentId": "clear_type" } ] } } } ] }reset
如果配置了resetValue,则重置时使用resetValue的值,否则使用初始值。
{ "type": "form", "debug": true, "data": { "abc": { "type": "c" } }, "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "id": "reset_type", "options": [ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c"} ], "value": "b" }, { "type": "button", "label": "重置", "onEvent": { "click": { "actions": [ { "actionType": "reset", "componentId": "reset_type" } ] } } } ] }reload
只有选择器模式支持,即配置source,用于重新加载选择器的数据源。组件侧的reload方法会透传给 HOC 提供的reloadOptions(reload 透传),底层 reloadOptions 实现 会区分"纯变量表达式 source(重新从数据域取值)"与"接口 source(重新请求)"两种路径。
{ "type": "form", "debug": true, "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "id": "reload_type", "source": "/api/mock2/form/getOptions?waitSeconds=1" }, { "type": "button", "label": "重新加载", "onEvent": { "click": { "actions": [ { "actionType": "reload", "componentId": "reload_type" } ] } } } ] }setValue
{ "type": "form", "debug": true, "body": [ { "type": "button-group-select", "label": "选项", "name": "type", "id": "setvalue_type", "options": [ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c"} ], "value": "b" }, { "type": "button", "label": "赋值", "onEvent": { "click": { "actions": [ { "actionType": "setValue", "componentId": "setvalue_type", "args": { "value": "c" } } ] } } } ] }可视化编辑与相关资源
除 JSON 配置外,amis 可视化编辑器也内置了该组件的插件:编辑器插件定义 将组件命名为"按钮点选",默认脚手架即一份带options的button-group-selectSchema,编辑面板中可直接维护选项、btnLevel、事件与动作,其事件元数据同样声明了change事件的value参数结构。相关可深入阅读的仓库文件:
- 渲染器实现:packages/amis/src/renderers/Form/ButtonGroupSelect.tsx
- 选项控件通用 HOC(source 加载、多选、值格式化):packages/amis-core/src/renderers/Options.tsx
- 按钮组基础类型定义(btnLevel/vertical/tiled 等):packages/amis/src/renderers/ButtonGroup.tsx
- 单元测试:packages/amis/tests/renderers/Form/buttonGroupSelect.test.tsx
- 按钮组样式:packages/amis-ui/scss/components/_button-group.scss
【免费下载链接】amis前端低代码框架,通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考