You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3搭配Vuelidate2时v$.FormData.name.$model不更新问题排查

为何v$.FormData.name.$model无法随表单输入同步更新?

问题背景

近期在将Vue 2应用升级至Vue 3的过程中遇到Vuelidate运行异常:

  • v$.FormData.name.$model始终仅保留初始值,不会随用户输入同步更新
  • v$.FormData.$model.name可以获取到最新的表单值,但该路径下不包含Vuelidate的校验属性与方法
    当前已将表单控件改造为使用<script setup>语法的SFC单文件组件,父子组件仍采用Options API编写,尝试过直接将v$.FormData.name.$model作为v-model绑定值传入组件,问题仍未解决。

核心实现代码

const FormData = reactive({});
const rules = reactive(Validations); // { FormData : { name: {}...
const v$ = useVuelidate(rules, { FormData }, { $autoDirty: true, $lazy: true });

...

watch(
  FormData,
  (oldValue, newValue) => {
    v$.value.FormData[control.vModel].$touch();
    emit("event_form_updated", {
      attributeName: props.control.vModel,
      model: v$.value.FormData[control.vModel],
    });
  },
  { deep: true }
);

...
<span>
  <component
        :is="components[control.component]"
        :control="control"
        :options="control.options"
        :values="control.value"
        v-model="FormData[control.vModel]"
        :v="v$.FormData[control.vModel]"
        v-show="showCtrl(control)"
        :tab-index="100 * (index + 1)"
      />
</span>

问题原因

核心问题出在FormData初始化时传入的是空对象:
Vuelidate在useVuelidate执行初始化阶段,会遍历传入的state对象的已有属性,为每个匹配校验规则的字段生成独立的响应式$model代理,实现值和校验状态的双向同步。如果字段是初始化完成后才动态添加到FormData上的,Vuelidate不会自动为这些后加的字段生成独立的$model代理,只会在顶层$model(也就是整个FormData的代理)上同步最新值,就会出现单字段路径下$model不更新、顶层路径能拿到值的现象。

修复方案

  • 优先方案:初始化FormData时提前声明所有表单字段的初始值,哪怕是空字符串、空数组这类默认值,保证Vuelidate初始化时能识别到所有字段,为每个字段生成正常同步的$model代理。示例:
    const FormData = reactive({
      name: '',
      // 把Validations里FormData下配置的所有字段都在这里提前声明初始值
    })
    
  • 最佳实践调整:表单组件的v-model直接绑定对应校验节点的$model,替代绑定原始FormData属性。开启$autoDirty: true配置后,通过$model更新值会自动标记字段脏状态,可以删掉原有watch里手动调用$touch()的冗余逻辑。调整后的组件绑定写法:
    <component
          :is="components[control.component]"
          :control="control"
          :options="control.options"
          :values="control.value"
          v-model="v$.FormData[control.vModel].$model"
          :v="v$.FormData[control.vModel]"
          v-show="showCtrl(control)"
          :tab-index="100 * (index + 1)"
        />
    
  • 动态字段兼容方案:如果业务场景确实需要动态增减表单字段、无法提前声明所有字段,就不要混用路径取值:读取表单最新值统一走v$.FormData.$model[字段名],读取校验方法、校验状态属性统一走v$.FormData[字段名]即可。

内容的提问来源于stack exchange,提问作者Nathan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:06:21