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

Vue中使用VeeValidate更新嵌套对象表单的问题排查

问题分析与解决方案

核心问题

  1. VueQuery返回的data是ref包装对象,直接将其作为formValues的属性值时,VeeValidate无法正确识别嵌套对象的响应性,导致表单无法跟踪嵌套字段的变更。
  2. ZamFormField中手动传递initialValue给useField,会覆盖VeeValidate Form上下文传递的初始值,干扰字段的响应式绑定。
  3. BasicInfo组件的Options API写法与当前Composition API环境不统一,且未正确利用VeeValidate的表单上下文。

分步修复

1. 修复GeneralSettings.vue的初始值响应性

将VueQuery返回的ref值解构取出原始对象,再构建formValues,确保嵌套对象的响应性被VeeValidate正确识别:

<template>
  <div v-if="companyIsLoading || authIsLoading">Loading please wait...</div>
  <div v-else>
    <Form v-slot="{ values }" :initial-values="formValues">
      <div>
        <admin-info />
        <pre>{{ values }}</pre>
      </div>
      <q-separator class="q-mt-md" />
      <basic-info />
      <q-separator class="q-mt-md" />
    </Form>
  </div>
</template>

<script setup>
import useCompanyDetailsQuery from "src/composables/useCompanyDetailsQuery";
import useAuthInfoQuery from "src/composables/useAuthInfoQuery";
import AdminInfo from "./AdminInfo.vue";
import BasicInfo from "./BasicInfo.vue";
import { ref } from "vue";
import { Form } from "vee-validate";

const {
  data: companyData,
  isLoading: companyIsLoading,
} = useCompanyDetailsQuery();

const {
  data: authData,
  isLoading: authIsLoading,
} = useAuthInfoQuery();

// 解构ref的value值,构建完整的表单初始值
const formValues = ref({
  authData: authData.value,
  companyData: companyData.value,
});
</script>

2. 修复ZamFormField.vue的字段绑定

移除useField的initialValue配置,让VeeValidate通过Form上下文自动注入初始值,确保字段响应式正常:

<script setup>
import { toRef } from "vue";
import { useField } from "vee-validate";

const props = defineProps({
  type: {
    type: String,
    default: "text",
  },
  name: {
    type: String,
    required: true,
  },
  label: {
    type: String,
    required: true,
  },
  successMessage: {
    type: String,
    default: "",
  },
  placeholder: {
    type: String,
    default: "",
  },
});

const name = toRef(props, "name");
// 移除initialValue配置,由Form上下文自动传递初始值
const {
  value: inputValue,
  errorMessage,
  handleChange,
  meta,
} = useField(name);
</script>

<template>
  <div>
    <label :for="name">{{ label }}</label>
    <input
      :name="name"
      :id="name"
      :type="type"
      :value="inputValue"
      :placeholder="placeholder"
      @input="handleChange"
    />
    <!-- 可选:显示错误信息 -->
    <span v-if="errorMessage" style="color: red;">{{ errorMessage }}</span>
  </div>
</template>

<style scoped>
label {
  display: block;
  margin-bottom: 4px;
  width: 100%;
}

input {
  border-radius: 5px;
  padding: 10px 10px;
  width: 100%;
  border: 2px solid grey;
}
</style>

3. 优化BasicInfo.vue为Composition API(可选但推荐)

统一代码风格,同时确保组件正确接入VeeValidate的表单上下文:

<template>
  <div class="ContainerHeading q-pa-sm">
    {{ "Company Info" }}
  </div>
  <div class="shadow-2 q-pa-md">
    <section class="q-gutter-md row q-pa-sm">
      <ZamFormField
        name="companyData.company.basicInfo.name"
        label="Company Name"
        class="input-field"
      />

      <ZamFormField
        name="companyData.company.basicInfo.url"
        label="url"
        class="input-field"
      />

      <ZamFormField
        name="companyData.company.basicInfo.contactPhone"
        label="Phone Number"
        class="input-field"
      />
    </section>
  </div>
</template>

<script setup>
import ZamFormField from "components/ZamFormField.vue";
</script>

<style>
.input-field {
  width: 33%;
}
</style>

验证效果

修改完成后,嵌套字段companyData.company.basicInfo.*和authData.*都能正常跟踪变更,表单values会实时更新输入内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 08:36:23