如何在vee-validate中结合使用Vue 3.4的defineModel?
如何在vee-validate中结合Vue 3.4的defineModel实现表单字段关联(避免重复watch)
你可以通过以下几种更简洁的方式实现defineModel与vee-validate字段的关联,无需为每个字段手动编写watch:
方案1:计算属性双向桥接(单字段推荐)
用计算属性作为中间层,同时同步defineModel和vee-validate的字段ref,自动处理双向更新,代码更简洁集中。
<template> <form class="flex flex-col gap-6 m-6"> <div class="flex flex-col gap-2"> <label for="businessName">Business Name</label> <InputText id="businessName" v-model="businessNameSync" v-bind="businessNameAttrs" /> <div class="text-xs text-red-500"> {{ errors.businessName }} </div> </div> <Button @click="handleClick">Validate</Button> </form> </template> <script setup lang="ts"> import { computed } from 'vue'; import { z } from 'zod'; import { toTypedSchema, useForm } from 'vee-validate'; // 组件的v-model字段 const businessName = defineModel<string>('businessName'); const formSchema = toTypedSchema( z.object({ businessName: z .string({ required_error: 'Business Name is required' }) .min(1, { message: 'Business Name is required' }), }) ); const { errors, defineField, validate } = useForm({ validationSchema: formSchema, }); // 获取vee-validate的字段ref和属性 const [businessNameVee, businessNameAttrs] = defineField('businessName'); // 双向同步defineModel与vee-validate字段 const businessNameSync = computed({ get() { return businessName.value; }, set(val) { businessName.value = val; businessNameVee.value = val; }, }); const handleClick = () => { validate(); }; </script>
方案2:批量字段同步(多字段表单推荐)
如果表单字段较多,可以通过遍历字段列表实现批量双向同步,避免重复代码:
<template> <form class="flex flex-col gap-6 m-6"> <div class="flex flex-col gap-2"> <label for="businessName">Business Name</label> <InputText id="businessName" v-model="formModel.businessName" v-bind="fieldAttrs.businessName" /> <div class="text-xs text-red-500"> {{ errors.businessName }} </div> <label for="email">Email</label> <InputText id="email" v-model="formModel.email" v-bind="fieldAttrs.email" /> <div class="text-xs text-red-500"> {{ errors.email }} </div> </div> <Button @click="handleClick">Validate</Button> </form> </template> <script setup lang="ts"> import { watch } from 'vue'; import { z } from 'zod'; import { toTypedSchema, useForm } from 'vee-validate'; // 组件的对象类型v-model const formModel = defineModel<{ businessName: string; email: string }>(); const formSchema = toTypedSchema( z.object({ businessName: z.string().min(1, 'Business Name is required'), email: z.string().email('Invalid email format'), }) ); const { errors, defineField, validate, values } = useForm({ validationSchema: formSchema, initialValues: formModel.value, }); // 批量定义字段并存储属性 const fieldAttrs: Record<string, any> = {}; const fieldRefs: Record<string, any> = {}; ['businessName', 'email'].forEach(key => { const [ref, attrs] = defineField(key); fieldRefs[key] = ref; fieldAttrs[key] = attrs; }); // 同步defineModel到vee-validate watch(formModel, (newVal) => { Object.entries(newVal).forEach(([key, val]) => { fieldRefs[key].value = val; }); }, { deep: true }); // 同步vee-validate到defineModel(按需开启) watch(values, (newVal) => { Object.assign(formModel.value, newVal); }, { deep: true }); const handleClick = () => { validate(); }; </script>
方案3:直接将defineModel作为vee-validate数据源(最彻底)
让vee-validate直接使用defineModel作为表单模型,无需额外同步逻辑,本质上是把defineModel包装成符合vee-validate要求的对象结构:
<template> <form class="flex flex-col gap-6 m-6"> <div class="flex flex-col gap-2"> <label for="businessName">Business Name</label> <InputText id="businessName" v-model="businessName" v-bind="businessNameAttrs" /> <div class="text-xs text-red-500"> {{ errors.businessName }} </div> </div> <Button @click="handleClick">Validate</Button> </form> </template> <script setup lang="ts"> import { z } from 'zod'; import { toTypedSchema, useForm } from 'vee-validate'; const businessName = defineModel<string>('businessName'); const formSchema = toTypedSchema( z.object({ businessName: z.string().min(1, 'Business Name is required'), }) ); // 包装defineModel为vee-validate可识别的模型结构 const formModel = { get businessName() { return businessName.value; }, set businessName(val) { businessName.value = val; }, }; const { errors, defineField, validate } = useForm({ validationSchema: formSchema, model: formModel, initialValues: { businessName: businessName.value }, }); const [, businessNameAttrs] = defineField('businessName'); const handleClick = () => { validate(); }; </script>
内容的提问来源于stack exchange,提问作者TinyTiger
相关产品推荐
相关产品推荐

