Checkbox 复选框
MCheckbox 与 MCheckboxGroup 是一对组合:单个复选框负责「是 / 否」,复选框组负责「从若干项里挑若干项」。组件内部通过 provide / inject 通信,因此同一个 MCheckbox 放在组内外时用的是两套完全不同的取值与抛事件逻辑。
代码演示
基础用法
上面是独立使用的 MCheckbox(v-model 为 boolean),下面是 MCheckboxGroup + 带 value 的子项(v-model 为数组)。
点击任意一项,观察自己维护的两个 ref 如何变化。
<script setup lang="ts">
import { ref } from 'vue'
const agree = ref(false)
const picked = ref<(string | number | boolean)[]>(['read'])
</script>
<template>
<div class="m-row-demo--col">
<MCheckbox v-model="agree">已阅读并同意《用户协议》</MCheckbox>
<MCheckboxGroup v-model="picked">
<MCheckbox value="read">可读</MCheckbox>
<MCheckbox value="write">可写</MCheckbox>
</MCheckboxGroup>
</div>
</template>复选框组
组的 color / size 会下发给所有子项,vertical 改为纵向排列,子项可用同名属性单独覆盖。
<script setup lang="ts">
import { ref } from 'vue'
const picked = ref<(string | number | boolean)[]>(['vue', 'ts'])
const stacks = [
{ value: 'vue', label: 'Vue' },
{ value: 'react', label: 'React' },
{ value: 'ts', label: 'TypeScript' },
{ value: 'rust', label: 'Rust' },
]
</script>
<template>
<div class="m-row-demo--col">
<MCheckboxGroup v-model="picked" color="secondary" size="large" vertical>
<MCheckbox v-for="stack in stacks" :key="stack.value" :value="stack.value">
{{ stack.label }}
</MCheckbox>
</MCheckboxGroup>
<span>当前选中:{{ picked.join('、') || '(空数组)' }}</span>
</div>
</template>半选状态
indeterminate 只改变勾选角标的图形与 aria-checked,配合「全选」联动使用。
<script setup lang="ts">
import { computed, ref } from 'vue'
const items = ['设计', '开发', '测试']
const picked = ref<(string | number | boolean)[]>(['设计'])
const allChecked = computed(() => picked.value.length === items.length)
const indeterminate = computed(() => picked.value.length > 0 && !allChecked.value)
function toggleAll(checked: boolean) {
picked.value = checked ? [...items] : []
}
</script>
<template>
<div class="m-row-demo--col">
<MCheckbox
:model-value="allChecked"
:indeterminate="indeterminate"
@change="toggleAll">
全选
</MCheckbox>
<MCheckboxGroup v-model="picked">
<MCheckbox v-for="item in items" :key="item" :value="item">{{ item }}</MCheckbox>
</MCheckboxGroup>
<span>选中 {{ picked.length }} / {{ items.length }}</span>
</div>
</template>禁用
独立的复选框与整组都可以禁用,禁用后点击不再触发任何事件。
<script setup lang="ts">
import { ref } from 'vue'
const checked = ref(true)
const unchecked = ref(false)
const groupPicked = ref<(string | number | boolean)[]>(['a'])
</script>
<template>
<div class="m-row-demo--col">
<MCheckbox v-model="checked" disabled>独立禁用(已选中)</MCheckbox>
<MCheckbox v-model="unchecked" disabled>独立禁用(未选中)</MCheckbox>
<MCheckboxGroup v-model="groupPicked" disabled>
<MCheckbox value="a">整组禁用 A</MCheckbox>
<MCheckbox value="b">整组禁用 B</MCheckbox>
</MCheckboxGroup>
</div>
</template>颜色与尺寸
六种语义色与三档尺寸,组内继承时可被单项覆盖。
<script setup lang="ts">
import { reactive, ref } from 'vue'
const colors = ['primary', 'secondary', 'success', 'warning', 'error', 'info'] as const
const byColor = reactive<Record<string, boolean>>({
primary: true,
secondary: true,
success: true,
warning: true,
error: true,
info: true,
})
const small = ref(true)
const normal = ref(true)
const large = ref(true)
const inherited = ref<(string | number | boolean)[]>(['a'])
</script>
<template>
<div class="m-row-demo--col">
<div class="m-row-demo">
<MCheckbox v-for="color in colors" :key="color" v-model="byColor[color]" :color="color">
{{ color }}
</MCheckbox>
</div>
<div class="m-row-demo">
<MCheckbox v-model="small" size="small" color="primary">small</MCheckbox>
<MCheckbox v-model="normal" size="default" color="primary">default</MCheckbox>
<MCheckbox v-model="large" size="large" color="primary">large</MCheckbox>
</div>
<MCheckboxGroup v-model="inherited" color="error" size="large">
<MCheckbox value="a">继承组的 error / large</MCheckbox>
<MCheckbox value="b" color="info" size="small">单项覆盖为 info / small</MCheckbox>
</MCheckboxGroup>
</div>
</template>API
MCheckbox Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value | CheckboxValue | undefined(未提供) | 组内项值:在 MCheckboxGroup 内用于维护选中数组 |
modelValue | boolean | undefined(未提供) | 独立使用时的选中状态(v-model,boolean);组内忽略此值 |
indeterminate | boolean | false | 半选状态:勾选角标显示为横线(通常用于「全选」联动) |
name | string | undefined(未提供) | 原生 input 的 name |
disabled | boolean | false | 是否禁用 |
color | CheckboxColor | undefined(组内继承,独立时回落 'primary') | 选中态颜色 |
size | CheckboxSize | undefined(组内继承,独立时回落 'default') | 尺寸 |
MCheckboxGroup Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | CheckboxValue[] | undefined(内部按 [] 处理) | 选中值数组(v-model) |
disabled | boolean | false | 是否禁用整组 |
color | CheckboxColor | undefined(内部回落 'primary') | 组内 MCheckbox 的统一颜色 |
size | CheckboxSize | undefined(内部回落 'default') | 组内 MCheckbox 的统一尺寸 |
vertical | boolean | false | 纵向排列 |
MCheckbox Events
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: boolean | 独立使用时选中状态变化 |
change | value: boolean | 独立使用时选中状态变化 |
MCheckboxGroup Events
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: CheckboxValue[] | 选中数组变化(勾选 / 取消) |
change | value: CheckboxValue[] | 选中数组变化(勾选 / 取消) |
Slots
| 插槽 | 参数 | 说明 |
|---|---|---|
default | 无 | MCheckbox 的标签文本;MCheckboxGroup 的子项列表 |
类型定义
export type CheckboxColor =
| 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info';
export type CheckboxSize = 'small' | 'default' | 'large';
export type CheckboxValue = string | number | boolean;
export interface CheckboxGroupContext {
modelValue: Ref<CheckboxValue[]>;
color: CheckboxColor;
size: CheckboxSize;
disabled: boolean;
toggleValue: (value: CheckboxValue, checked: boolean) => void;
}Expose:两个组件源码均未暴露实例方法。
组内使用:值从哪来,事件由谁抛
| 场景 | v-model 类型 | 是否必须传 value | 事件由谁抛出 |
|---|---|---|---|
| 独立使用 | boolean | 不需要 | MCheckbox 自己抛 update:modelValue / change |
放在 MCheckboxGroup 内 | CheckboxValue[](绑定在组上) | 必须 | 只有 MCheckboxGroup 抛,子组件不抛 |
组内子项的选中状态由 group.modelValue.value.includes(props.value) 计算,勾选 / 取消统一走组的 toggleValue(value, checked)。
使用建议
半选是纯展示状态
indeterminate 只影响角标图形与 aria-checked="mixed",不参与 checked 的计算,也不会随点击自动清除。搭配「全选」使用时,请把 indeterminate 写成由选中数量推导的 computed:
<MCheckbox
:model-value="allChecked"
:indeterminate="picked.length > 0 && !allChecked"
@change="(checked) => (picked = checked ? [...all] : [])" />组内不传 value 会出错
组内子项的选中判断是 includes(props.value)。不传 value 时每一项都以 undefined 参与比对,会出现「点一项全部选中」的错误表现。放进组就必须给 value。
组内子组件不再抛事件
在 MCheckboxGroup 里给子项写 @change 是无效的——子组件只在独立使用时才 emit,组内一律交给组的 toggleValue 处理。需要感知变化请监听组的事件。
组禁用会吞掉点击
组 disabled 为真时 toggleValue 直接返回,子项的 disabled 也会被置为禁用态。此时子项的 @change 不会被触发。
相关组件
- Radio 单选框:同样「组 + 子项」的机制,但取值为单值、互斥。
- Switch 开关:只需一个布尔开关时比复选框更醒目。
- Select 选择器:选项数量多到不适合全部铺开时改用下拉。