Element Plus 的 ElRadioGroup 和 ElCheckboxGroup 通过插槽 + provide/inject + v-model 实现子项值自动收集,轻量解耦;子组件注入上下文并注册自身,双向绑定父级 modelValue,响应式驱动选中状态同步,支持跨层级嵌套场景。

Element Plus 的 ElRadioGroup 和 ElCheckboxGroup 能自动收集子项(如 ElRadio 或 ElCheckbox)的值,核心在于父子组件通过插槽 + provide/inject + v-model 双向绑定协同完成通信。不依赖事件总线或全局状态,轻量且解耦。
插槽透传与子组件注册
父组件(如 MyRadioGroup)用 <slot></slot> 渲染子项,并在 setup 中调用 provide 暴露注册方法:
const { provide } = defineComponent({
setup(props, { slots }) {
const modelValue = ref(props.modelValue)
const register = (child: RadioItem) => {
// 缓存子组件实例,用于后续同步值
children.push(child)
}
provide('radioGroupContext', {
modelValue,
register,
onChange: (val: any) => {
modelValue.value = val
emit('update:modelValue', val)
}
})
return () => h('div', { class: 'my-radio-group' }, slots.default?.())
}
})
子组件主动注入并绑定 v-model
子组件(如 MyRadio)在 setup 中用 inject 获取上下文,并将自身“注册”到父组;同时把 v-model 绑定到父级的 modelValue:
- 通过
inject('radioGroupContext')拿到modelValue和onChange - 在
onMounted调用context.register({ value, id, ... }) - 用
computed建立双向映射:model: { get: () => context.modelValue.value, set: v => context.onChange(v) }
值同步与选中逻辑处理
父组件不直接操作子组件 DOM,而是靠响应式驱动渲染。子组件根据当前 modelValue 判断是否选中:
-
MyRadio的isChecked是computed(() => props.value === context.modelValue.value) - 点击时触发
context.onChange(props.value),父组件modelValue更新 → 所有子组件自动重算isChecked - 无需手动遍历子组件、也不需要
$refs或ref列表更新状态
支持非直接子组件(嵌套插槽场景)
若子项被包装(例如 <MyRadioGroup><template #default><div><MyRadio /></div></template></MyRadioGroup>),需确保子组件仍能访问 inject 上下文。Vue 3 的 provide/inject 是跨层级的,只要在渲染链路中未被新的 provide 覆盖即可生效。必要时可在中间 wrapper 组件中透传 context:
const ctx = inject('radioGroupContext')
if (ctx) {
provide('radioGroupContext', ctx) // 显式向下透传
}

















