Skip to content

title: 动态表单「已勾选仍提示必填」的两处修复 date: 2025-09-05 tags: [Vue3, Ant Design Vue, 表单校验, 组件封装]


问题概述

复选框(a-checkbox-group)在 必填 时,即使勾选了第一项仍提示“请选择”。根因有两点:

  1. 你的 Checkbox 包装组件把 v-model:value 定义成了 boolean(默认 false),而 a-checkbox-group 需要 数组
  2. 通用的 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 漏判。

应用以上两处修改后,勾选第一项即可通过校验,不再提示“请选择”。

本站总访问