Vue2 校验不通过的表单,赋正确的值后,再次校验结果不变

发布时间 2023-12-14 16:48:03作者: 幻世、

前言

在工作中遇到了这个问题,多次排查,耗费了不少时间才解决这个问题。问题的解决很简单,但发现根本原因还是有点困难,因此在此做个记录,以防忘记。

问题发现步骤

例如有以下 Ant Design Vue 表单

<a-form-model ref="formRef" :model="model">

  <a-form-model-item label="姓名" prop="name" :rules="[{ required: true, message: '请填写姓名', trigger: 'blur' }]">
    <a-input v-model="model.name" placeholder="请输入姓名"></a-input>
  </a-form-model-item>
  
  <a-form-model-item label="留言" prop="notes" :rules="[{ required: true, message: '请填写留言', trigger: 'blur' }]">
    <a-input v-model="model.notes" placeholder="请输入留言"></a-input>
  </a-form-model-item>
  
<a-form-model/>

然后进行以下步骤

1.留言项输入内容,然后通过 this.$refs.refForm.validate() 进行表单校验,这时候会报姓名项为必填项的错误;
2.然后通过事件为 model.name 赋值,例如 this.model = Object.assign(this.model, { name: '123' }),赋值后重新进行表单校验,此时依旧报姓名项为必填项的错误;

其他现象

3.打印 this.model ,得到的是正确的值

console.log(this.model) // { name: '123', notes: '之前输入的内容' }

4.直接在 input 输入框上填写内容,把内容从 ‘123’,改为 ‘test’,填写完后,刚填写的 ‘test’ 又变回了 ‘123’,打印 this.model ,得到的是新的值

console.log(this.model) // { name: 'test', notes: '之前输入的内容' }

后续判断为 this.model 对象失去了响应性。

解决

去搜相关内容,搜到的大都说 Object.assign() 会保留对象的响应性,直接赋值才会丢失响应性

this.model = Object.assign(this.model, { name: '123' }) // 保留响应性 ?
this.model = { name: '123', notes: '之前输入的内容' } // 丢失响应性 ?

但根据实际情况和这个问题的表现,证明 this.model = Object.assign(this.model, { name: '123' }) 这样也会丢失响应性。
最终的解决方法在官方文档 深入响应式原理 这部分

有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

所以实际是:

this.model = Object.assign(this.model, { name: '123' }) // 丢失响应性

this.model = Object.assign({}, this.model, { name: '123' }) // 保留响应性