Vant2 的 Radio 单选框是移动端 H5 项目里出镜率极高的组件之一,通常配合 RadioGroup 一同使用。刚接触它的同学往往会遇到这样的困惑:明明给 Radio 设置了 v-model,为什么数据没变?为什么传给后端的值变成了字符串?cell 类型又是怎么回事?这篇文章就把 Radio 的基本概念、核心配置和常见坑点一次性梳理清楚。

一、先弄清楚 Radio 和 RadioGroup 的关系
Vant2 中的 Radio 必须放在 <van-radio-group> 内部才能正常工作,这一点和原生 HTML 的 radio 加 name 属性是类似的思路。RadioGroup 负责管理"当前选中的是哪一项",也就是持有 v-model 绑定的数据;而单个 Radio 只负责展示某个选项,并通过 name 属性告诉父组件"我被选中时对应的值是什么"。
看一个最小可运行示例就明白了:
<template>
<van-radio-group v-model="radio">
<van-radio name="a">选项A</van-radio>
<van-radio name="b">选项B</van-radio>
</van-radio-group>
</template>
<script>
export default {
data() {
return {
radio: 'a'
};
}
};
</script>这段代码里,v-model 绑定在 RadioGroup 上,初始值是字符串 'a',所以页面渲染出来后选项 A 默认被选中。当用户点击选项 B 时,RadioGroup 会把 radio 的值更新为 'b'。整个通信流程是:点击 Radio 触发内部的 click 事件,Radio 向上冒泡通知 RadioGroup,RadioGroup 修改绑定的数据,再通过 props 下发新的选中状态。
这里有个非常关键的点:name 的类型可以是字符串,也可以是数字。如果 name 传的是数字 :name="1",而 v-model 初始值是字符串 '1',那么组件内部用严格相等去比较时会对不上,导致默认选中失效。所以绑定的数据和 name 的类型务必保持一致,这是新手最常踩的第一个坑。
二、常用配置项与样式定制
Radio 本身提供了不少实用的 props,掌握下面这几个基本就能应付绝大多数场景:
- name:选项的唯一标识,选中后 v-model 就会变成这个值;
- shape:图标形状,可选
round(圆点)和square(方形),默认圆形; - disabled:禁用当前选项,禁用后点击无效且样式变灰;
- label-disabled:只禁用文本区域的点击,图标仍然可以点;
- icon-size:自定义图标大小,如
16px; - checked-color:选中状态的颜色,默认是主题蓝色。
下面这个例子演示了形状、颜色和禁用的组合用法:
<template>
<van-radio-group v-model="gender">
<van-radio :name="1" shape="square" checked-color="#07c160">男</van-radio>
<van-radio :name="2" shape="square" checked-color="#07c160">女</van-radio>
<van-radio :name="0" disabled>保密</van-radio>
<van-radio-group>
</template>
<script>
export default {
data() {
return {
gender: 1
};
}
};
</script>注意这里用了 :name="1" 这种绑定写法而不是 name="1"。两者的区别在于:不加冒号时传过去的是字符串 "1",加了冒号传的才是数字 1。传给后端接口时,如果对方要求整型,这个细节一定要留意。
除了自己写布局,Vant 还提供了 van-radio-group 与 Cell 单元格结合的方式。给 Radio 设置 label-disabled,再把它放进 van-cell 的 title 插槽,点击整行就能切换选中,交互体验更符合移动端习惯:
<van-radio-group v-model="result">
<van-cell-group>
<van-cell title="苹果" clickable @click="result = '1'">
<van-radio :name="'1'" label-disabled />
</van-cell>
<van-cell title="香蕉" clickable @click="result = '2'">
<van-radio :name="'2'" label-disabled />
</van-cell>
</van-cell-group>
</van-radio-group>三、事件监听与动态数据渲染
RadioGroup 提供了 change 事件,在选中项变化时触发,参数就是新选中的 name 值。实际业务里经常需要在切换时发请求或者联动其他表单项,这时就该用 change 而不是 watch 数据:
<template>
<van-radio-group v-model="city" @change="onChange">
<van-radio v-for="item in cityList"
:key="item.id"
:name="item.id">
{{ item.name }}
</van-radio>
</van-radio-group>
</template>
<script>
export default {
data() {
return {
city: null,
cityList: [
{ id: 101, name: '北京' },
{ id: 102, name: '上海' },
{ id: 103, name: '深圳' }
]
};
},
methods: {
onChange(val) {
console.log('选中了:', val);
// 这里可以触发联动查询等业务逻辑
}
}
};
</script>配合 v-for 渲染动态列表是真实项目中最常见的写法。数据从接口回来后直接循环渲染,name 绑定接口返回的 id,v-model 初始值设为 null 或不设,表示默认不选中任何项。
还有一个容易忽略的场景:RadioGroup 支持 direction 属性,设置为 horizontal 后选项会横向排列,默认是纵向的。做筛选栏时这个属性很实用。另外 RadioGroup 上也可以直接设置 disabled,一次性禁用整组选项,不用挨个去给 Radio 加。
四、常见疑问集中解答
问题一:点击单选框没反应,v-model 不更新? 首先检查 Radio 是不是漏了包在 RadioGroup 里,单独使用的 Radio 是无法维护选中状态的。其次检查是否误用了 :disabled,以及 name 与绑定值类型是否一致。
问题二:默认选中不生效? 九成原因是类型不匹配。绑定值是 '1' 而 name 是数字 1,严格比较不相等就不会选中。统一使用 :name 绑定,并保证初始值类型对应即可。
问题三:想自定义选中图标怎么办? Radio 提供了两个插槽,icon 插槽可以完全接管图标的渲染,通过作用域插槽拿到的 checked 变量区分选中与未选中状态,配合 van-icon 或自己的图片就能实现个性化样式。
问题四:怎么在提交表单前校验必选? 简单做法是在提交方法里判断绑定值是否为空,为空就 this.$toast('请选择xxx') 并阻断提交;复杂表单则建议搭配 van-form 的 rules 校验,把 RadioGroup 作为表单项纳入统一校验流程。
总的来说,Vant2 的 Radio 组件本身不复杂,核心就是"RadioGroup 管数据、Radio 管展示"这一层关系。把 name 类型一致、组内包裹、change 事件这几个要点记牢,基本就不会再踩坑了。
Vant2 Radio单选框vant组件修改时间:2026-09-13 19:06:58