如何在Vue3嵌套表单组件层级中传递Vuelidate验证错误?
问题描述
我正在使用Vue 3和Vuelidate,刚接触Vue框架,希望构建如下组件层级:
- Page组件:维护数据模型、定义输入项、字段验证规则及表单验证通过后的执行动作;
- Form组件:作为插槽容器,使用Vuelidate完成所有字段的验证,验证通过时触发事件;
- Input组件:展示绑定模型数据的输入框及错误容器(后续将改为动态组件)。
尝试实现后,无法将Form组件内的Vuelidate验证错误传递给Input组件,请问问题出在哪里?是否是结构设计问题?以下是我的三个组件实现代码:
Page组件
<!-- Page.vue --> <template> <Form :data="data" :validations="validations" > <Input v-model="data.field" error="TODO how to pass the error to this field ?" ></Input> </Form> <pre>{{ data }}</pre> </template> <script> import Form from "./Form.vue" import Input from "./Input.vue" import { required } from '@vuelidate/validators' export default { components: { Form, Input }, data() { return { data: { field: null, }, validations : { field: { required }, }, } }, } </script>
Form组件
<!-- Form.vue --> <template> <form @submit.stop.prevent="submit" > <slot></slot> </form> <pre>{{ v$.$errors }}</pre> </template> <script> import { useVuelidate } from '@vuelidate/core' export default { setup() { return { v$: useVuelidate(), } }, props: { data: { required: true, }, validations: { required: true, }, }, validations() { return this.validations }, methods: { async submit (event) { const isValid = await this.v$.$validate() console.log(isValid) }, }, } </script>
Input组件
<!-- Input.vue --> <template> <input type="text" v-model="modelLocal" > <span>{{ error }}</span> <pre>{{ modelLocal }}</pre> </template> <script> export default { emits: ['update:modelValue'], props: { modelValue: { required: true, }, error: { required: true, } }, computed: { modelLocal: { get() { return this.modelValue }, set(value) { this.$emit('update:modelValue', value) } }, }, } </script>
问题分析与修复方案
核心问题
- Vuelidate实例未绑定数据与规则:原Form组件中
useVuelidate()未传入验证规则和数据模型,导致v$实例无法关联到传入的data和validationsprops。 - 插槽作用域隔离:Input组件在Page组件作用域渲染,无法直接访问Form内部的v$实例,需通过作用域插槽传递验证状态。
- Input组件的error限制不合理:原Input要求error为必填项,但初始无错误时无法满足,需调整prop配置。
修复后的组件代码
1. Form组件(关键修改)
- 正确初始化Vuelidate实例,绑定传入的data和validations
- 通过作用域插槽暴露v$实例,让父组件获取字段验证错误
<!-- Form.vue --> <template> <form @submit.stop.prevent="submit"> <!-- 作用域插槽传递v$实例 --> <slot :v="$v"></slot> </form> <pre>{{ v$.$errors }}</pre> </template> <script> import { useVuelidate } from '@vuelidate/core' export default { setup(props) { // 绑定验证规则与数据模型 const v$ = useVuelidate(props.validations, props.data) return { v$ } }, props: { data: { required: true, type: Object }, validations: { required: true, type: Object }, }, methods: { async submit() { const isValid = await this.v$.$validate() console.log(isValid) // 验证通过触发自定义事件,供Page组件处理后续逻辑 if (isValid) this.$emit('submit-success') }, }, } </script>
2. Page组件(关键修改)
- 使用作用域插槽接收Form传递的v$实例
- 将对应字段的验证错误传递给Input组件
<!-- Page.vue --> <template> <Form :data="data" :validations="validations" @submit-success="handleSubmitSuccess" <!-- 接收作用域插槽的v$实例 --> v-slot="{ v$ }" > <Input v-model="data.field" <!-- 传递对应字段的第一个错误信息 --> :error="v$.field?.$errors[0]?.$message" ></Input> </Form> <pre>{{ data }}</pre> </template> <script> import Form from "./Form.vue" import Input from "./Input.vue" import { required } from '@vuelidate/validators' export default { components: { Form, Input }, data() { return { data: { field: null, }, validations : { field: { required }, }, } }, methods: { handleSubmitSuccess() { // 表单验证通过后的业务逻辑 console.log('表单验证通过,执行后续动作') } } } </script>
3. Input组件(关键修改)
- 取消error的必填限制,增加默认值避免初始报错
- 仅当有错误时显示错误信息
<!-- Input.vue --> <template> <input type="text" v-model="modelLocal" > <span v-if="error" class="error-text">{{ error }}</span> <pre>{{ modelLocal }}</pre> </template> <script> export default { emits: ['update:modelValue'], props: { modelValue: { required: true, }, error: { required: false, default: '' } }, computed: { modelLocal: { get() { return this.modelValue }, set(value) { this.$emit('update:modelValue', value) } }, }, } </script> <style scoped> .error-text { color: red; margin-left: 8px; } </style>
额外优化建议
- 若需要实时验证(输入时触发),可在Form组件的setup中添加监听:
// Form.vue的setup中 import { watch } from 'vue' watch(props.data, () => { v$.$validate() }, { deep: true })
- 可封装错误信息处理逻辑,比如将多个错误拼接成字符串,或根据验证规则返回自定义提示。
内容的提问来源于stack exchange,提问作者Aurelien
相关产品推荐
相关产品推荐

