Appearance
title: 动态表单「已勾选仍提示必填」的两处修复 date: 2025-09-05 tags: [Vue3, Ant Design Vue, 表单校验, 组件封装]
问题概述
复选框(a-checkbox-group)在 必填 时,即使勾选了第一项仍提示“请选择”。根因有两点:
- 你的
Checkbox包装组件把v-model:value定义成了 boolean(默认false),而a-checkbox-group需要 数组; - 通用的
required: true规则对 数组长度 不做判断,需要为复选框补一条“至少选一项”的自定义校验。
下面给出最小修改代码片段(仅展示需要调整的部分)。
说明:按你的偏好,复杂逻辑的代码段我在上一行加了注释。
修改 1:Checkbox 组件把模型改为数组
把 defineModel<boolean> 改为 defineModel<any[]>,默认值设为 [],并确保内部状态是数组。
ts
// 复杂:CheckboxGroup 期望数组类型;默认值必须为 [],否则 antd 校验无法判定“是否已选择”
const model = defineModel<any[]>("value", { default: [] });
const innerValue = ref<any[]>(Array.isArray(model.value) ? model.value : []);
watch(model, (v) => (innerValue.value = Array.isArray(v) ? v : []));
watch(innerValue, (v) => (model.value = Array.isArray(v) ? v : []));修改 2:为复选框补充“至少选一项”的校验规则
在 getValidationRules 中,为 controlType === 'checkbox' 增加自定义校验(在你现有的特殊控件分支里添加一段即可)。
ts
// 复杂:CheckboxGroup 的必填校验——至少选择 1 项
} else if (field.controlType === 'checkbox') {
rules.push({
validator: async (_: any, v: any[]) => {
const ok = Array.isArray(v) && v.length > 0
if (!ok && field.required)
return Promise.reject(t('files.form.rule.required', { label: field.label }))
return Promise.resolve()
},
trigger: ['change', 'blur'],
})放置位置建议:就放在你现有的
/* 特殊控件校验 */分支里,和stockholder / image / file同级。
可选增强:初始化把错误类型矫正为数组
若后端历史数据里该字段可能是 false/null/''/单值,可以在你已有的 watch(_fields, ...) 预处理里顺手矫正为数组,避免初始值导致“已选中但校验失败”。
ts
// 复杂:把历史/异常初始值统一矫正为 CheckboxGroup 需要的数组
} else if (f.controlType === 'checkbox') {
const v = formData[f.name]
if (!Array.isArray(v)) formData[f.name] = v == null || v === false ? [] : [v]
}结论
- 关键修复在于:复选框的
v-model类型必须是 数组; - 规则层面补充“至少一项”的自定义校验,避免通用
required漏判。
应用以上两处修改后,勾选第一项即可通过校验,不再提示“请选择”。