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

如何在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>

问题分析与修复方案

核心问题

  1. Vuelidate实例未绑定数据与规则:原Form组件中useVuelidate()未传入验证规则和数据模型,导致v$实例无法关联到传入的data和validations props。
  2. 插槽作用域隔离:Input组件在Page组件作用域渲染,无法直接访问Form内部的v$实例,需通过作用域插槽传递验证状态。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:27:15