Radio 单选框
MRadio 与 MRadioGroup 的机制与 Checkbox 一组同源,差别只在取值:组维护的是单值,子项通过 group.modelValue === props.value 判断自己是否被选中,因此天然互斥。独立使用时 MRadio 退化为一个布尔开关。
代码演示
基础用法
上面是独立使用的 MRadio(v-model 为 boolean),下面是 MRadioGroup + 带 value 的子项(v-model 为单值)。
<script setup lang="ts">
import { ref } from 'vue'
const accepted = ref(false)
const plan = ref<string | number | boolean>('m')
</script>
<template>
<div class="m-row-demo--col">
<MRadio v-model="accepted">独立使用</MRadio>
<MRadioGroup v-model="plan">
<MRadio value="s">S</MRadio>
<MRadio value="m">M</MRadio>
<MRadio value="l">L</MRadio>
</MRadioGroup>
</div>
</template>单选框组
组的 name 会下发给所有子项,vertical 改为纵向排列,color / size 也由组统一控制。
<script setup lang="ts">
import { ref } from 'vue'
const picked = ref<string | number | boolean>('standard')
const plans = [
{ value: 'basic', label: '基础版' },
{ value: 'standard', label: '标准版' },
{ value: 'pro', label: '专业版' },
]
</script>
<template>
<div class="m-row-demo--col">
<MRadioGroup
v-model="picked"
name="plan"
color="secondary"
size="large"
vertical>
<MRadio v-for="plan in plans" :key="plan.value" :value="plan.value">
{{ plan.label }}
</MRadio>
</MRadioGroup>
<span>当前选中值:{{ picked }}</span>
</div>
</template>禁用
既可以禁用组内某一个选项,也可以用组的 disabled 一次性禁用整组。
<script setup lang="ts">
import { ref } from 'vue'
const picked = ref<string | number | boolean>('standard')
const groupPicked = ref<string | number | boolean>('a')
</script>
<template>
<div class="m-row-demo--col">
<MRadioGroup v-model="picked" name="plan-mixed">
<MRadio value="basic">基础版</MRadio>
<MRadio value="standard" disabled>标准版(单项禁用)</MRadio>
<MRadio value="pro">专业版</MRadio>
</MRadioGroup>
<MRadioGroup v-model="groupPicked" disabled>
<MRadio value="a">整组禁用 A</MRadio>
<MRadio value="b">整组禁用 B</MRadio>
</MRadioGroup>
</div>
</template>颜色与尺寸
六种语义色与三档尺寸;组内继承的值可被单项覆盖。
<script setup lang="ts">
import { ref } from 'vue'
const colors = ['primary', 'secondary', 'success', 'warning', 'error', 'info'] as const
const pickedColor = ref<string | number | boolean>('primary')
const small = ref<string | number | boolean>('small')
const normal = ref<string | number | boolean>('default')
const large = ref<string | number | boolean>('large')
const inherited = ref<string | number | boolean>('a')
</script>
<template>
<div class="m-row-demo--col">
<MRadioGroup v-model="pickedColor" name="colors" vertical>
<MRadio v-for="color in colors" :key="color" :value="color" :color="color">
{{ color }}
</MRadio>
</MRadioGroup>
<div class="m-row-demo">
<MRadioGroup v-model="small" name="size-small" size="small">
<MRadio value="small">small</MRadio>
</MRadioGroup>
<MRadioGroup v-model="normal" name="size-default" size="default">
<MRadio value="default">default</MRadio>
</MRadioGroup>
<MRadioGroup v-model="large" name="size-large" size="large">
<MRadio value="large">large</MRadio>
</MRadioGroup>
</div>
<MRadioGroup v-model="inherited" name="inherit" color="error" size="large">
<MRadio value="a">继承组的 error / large</MRadio>
<MRadio value="b" color="info" size="small">单项覆盖为 info / small</MRadio>
</MRadioGroup>
</div>
</template>name 继承与原生表单
组把 name 下发给每个子项,所以单选框组可以直接参与原生表单提交,不需要额外的隐藏字段。
点击提交,FormData.get('plan') 取到的就是当前选中项的 value。
<script setup lang="ts">
import { ref } from 'vue'
const picked = ref<string | number | boolean>('standard')
const submitted = ref('(尚未提交)')
function onSubmit(event: Event) {
const data = new FormData(event.target as HTMLFormElement)
submitted.value = String(data.get('plan') ?? '(空)')
}
</script>
<template>
<form class="m-row-demo--col" @submit.prevent="onSubmit">
<MRadioGroup v-model="picked" name="plan">
<MRadio value="basic">基础版</MRadio>
<MRadio value="standard">标准版</MRadio>
<MRadio value="pro">专业版</MRadio>
</MRadioGroup>
<div class="m-row-demo">
<MButton variant="contained" color="primary" type="submit">提交</MButton>
<span>FormData.get('plan') = {{ submitted }}</span>
</div>
</form>
</template>API
MRadio Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value | RadioValue | undefined(未提供) | 单选值:在 MRadioGroup 内必须提供,用于与组激活值比对 |
modelValue | boolean | undefined(未提供) | 独立使用时的选中状态(v-model,boolean);组内忽略此值 |
name | string | undefined(组内可继承) | 原生 input 的 name(表单语义 / 同组互斥) |
disabled | boolean | false | 是否禁用 |
color | RadioColor | undefined(组内继承,独立时回落 'primary') | 选中态颜色 |
size | RadioSize | undefined(组内继承,独立时回落 'default') | 尺寸 |
MRadioGroup Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | RadioValue | undefined(未提供) | 当前选中值(v-model) |
name | string | undefined(未提供) | 原生 input 的 name,下发给组内所有 MRadio |
disabled | boolean | false | 是否禁用整组 |
color | RadioColor | undefined(内部回落 'primary') | 组内统一颜色 |
size | RadioSize | undefined(内部回落 'default') | 组内统一尺寸 |
vertical | boolean | false | 纵向排列:默认横向 flex 排列 |
MRadio Events
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: boolean | 独立使用时被选中(仅在选中时抛,取消不会抛) |
change | value: boolean | 独立使用时被选中(仅在选中时抛) |
MRadioGroup Events
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: RadioValue | 选中值变化(值未变化时不抛) |
change | value: RadioValue | 选中值变化 |
Slots
| 插槽 | 参数 | 说明 |
|---|---|---|
default | 无 | MRadio 的标签文本;MRadioGroup 的子项列表 |
类型定义
export type RadioColor =
| 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info';
export type RadioSize = 'small' | 'default' | 'large';
export type RadioValue = string | number | boolean;
export interface RadioGroupContext {
modelValue: Ref<RadioValue | undefined>;
color: RadioColor;
size: RadioSize;
disabled: boolean;
name?: string;
updateValue: (value: RadioValue) => void;
}Expose:两个组件源码均未暴露实例方法。
组内使用:与 Checkbox 组的差异
| 维度 | MCheckboxGroup | MRadioGroup |
|---|---|---|
v-model 类型 | CheckboxValue[](数组) | RadioValue(单值) |
| 子项选中判断 | group.modelValue.includes(value) | group.modelValue === value |
| 组内可否取消 | 可以(再次点击取消该项) | 不可以,只能切换到另一项 |
共同点:组内子项都必须传 value,且组内不再抛 update:modelValue / change,统一由组抛。
使用建议
选中态会带居中的涟漪反馈
MRadio 默认挂载 v-ripple(居中模式),点击时有 Material 涟漪动画,不需要额外配置。
组内不传 value 会互斥失效
组内判断是 group.modelValue === props.value。不传 value 时每一项都用 undefined 参与比对,会出现「全部同时选中」或「怎么点都选不中」的表现。
同一页面里多个组请给不同的 name
name 会透传到原生 input。多个单选框组共用同一个 name 时,浏览器会把它们当成一个原生单选组,与组件自己的状态判断产生冲突。要么每组用不同的 name,要么都不传。
重复选同一项不会抛事件
updateValue 在 value === props.modelValue 时直接返回。因此点击已选中项不会触发 change,需要「点击即上报」的行为请在业务侧自行处理。
相关组件
- Checkbox 复选框:同样的「组 + 子项」结构,但可多选。
- RadioButtonGroup 按钮式单选组:用按钮外观呈现单选的场景。
- Select 选择器:选项较多、需要收起时改用下拉。