Vue3 + Vee-Validate4:handleSubmit函数无法触发问题求助
问题
Vue新手,正在学习使用Composition API开发。使用VeeValidate 4进行表单验证和提交时,handleSubmit函数完全无法触发,已按照官方文档创建表单,但不清楚哪里出错。
代码示例
<template> <div class="modal-dialog modal-dialog modal-lg modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">Add Layout </h4> <a class="modal-close" @click="isModalOpen = !isModalOpen"><i class="fa fa-times"></i></a> </div> <form autocomplete="off" @submit="onSubmit"> <div class="modal-body"> <div class="row"> <div class="col-md-12 col-lg-12"> <div class="mb-3"> <label class="form-label">Layout Name:<span class="text-danger">*</span></label> <div class="form-group"> <input type="text" name="layoutName" v-model="layoutName" class="form-control" maxlength="50" placeholder="Enter Layout Name" :class="{ 'is-invalid': layoutNameError }" /> <div class="invalid-feedback">{{ layoutNameError }}</div> </div> </div> </div> <div class="col-md-6 col-lg-6 col-sm-12 col-xs-12"> <div class="mb-3"> <label class="form-label">Module:<span class="text-danger">*</span></label> <div class="form-group"> <Dropdown name="moduleId" v-model="moduleId" :options="moduleList" optionLabel="text" placeholder="Select Module" class="widthAll" @change="onChangeModule($event.value)" :editable="true" :filter="true" :showClear="true" /> </div> </div> </div> <div class="col-md-6 col-lg-6 col-sm-12 col-xs-12"> <div class="mb-3"> <label class="form-label">Sub Module:<span class="text-danger">*</span></label> <div class="form-group"> <Dropdown name="subModuleId" v-model="subModuleId" :options="subModuleList" optionLabel="text" placeholder="Select Sub Module" class="widthAll" :editable="true" :filter="true" :showClear="true" /> </div> </div> </div> <div class="col-md-6 col-lg-6 col-sm-12 col-xs-12"> <div class="mb-3"> <label class="form-label">Device Type:<span class="text-danger">*</span></label> <div class="form-group"> <Dropdown name="deviceTypeId" v-model="deviceTypeId" :options="deviceTypeList" optionLabel="text" placeholder="Select Device Type" class="widthAll" :editable="true" :filter="true" /> </div> </div> </div> <div class="col-md-6 col-lg-6 col-sm-12 col-xs-12"> <div class="mb-3"> <label class="form-label">Layout Type:<span class="text-danger">*</span></label> <div class="form-group"> <Dropdown name="layoutTypeId" v-model="layoutTypeId" :options="layoutTypeList" optionLabel="text" placeholder="Select Layout Type" class="widthAll" :editable="true" :filter="true" /> </div> </div> </div> <div class="col-md-12 col-lg-12"> <div class="mb-3"> <label class="form-label">Description:</label> <div class="form-group"> <input type="text" name="description" v-model="description" class="form-control" maxlength="50" placeholder="Enter description" :class="{ 'is-invalid': descriptionError }" /> <div class="invalid-feedback">{{ descriptionError }}</div> </div> </div> </div> </div> </div> <div class="modal-footer"> <div class="col-12 mt-3"> <button type="submit" class="btn btn-success me-2">Submit</button> <a href="javascript:;" class="btn btn-danger form-btns" @click="isModalOpen = false">Cancel</a> </div> </div> </form> </div> </div> </template> <script> import { ref, onMounted } from 'vue'; import * as Yup from 'yup'; import Dropdown from 'primevue/dropdown'; import InputMask from '@/views/shared/inputmask/inputmasktemplate.vue'; //Services import CommonService from '@/service/crmservice/commonService'; import ManageLayoutService from '@/service/crmservice/manageLayoutService'; import { useForm, useField } from 'vee-validate'; export default { name: 'ManageLayoutAddView', components: { InputMask, Dropdown }, props: { isModalOpen: Yup.boolean }, setup(props) { console.log(props) const commonService = ref(new CommonService()); const manageLayoutService = ref(new ManageLayoutService()); const layoutTypeKey = ref('layoutType'); const deviceTypeKey = ref('deviceType'); const moduleList = ref([]); const subModuleList = ref([]); const layoutTypeList = ref([]); const deviceTypeList = ref([]); const companyId = ref(null); const userId = ref(null); const layoutObj = ref({ layoutName: null, moduleId: null, subModuleId: null, deviceTypeId: null, layoutTypeId: null, description: null, }); const schema = Yup.object().shape({ layoutName: Yup.string().required('Layout Name is required'), moduleId: Yup.string().required('Module is required'), subModuleId: Yup.string().required('Sub Module is required'), deviceTypeId: Yup.string().required('Device Type is required'), layoutTypeId: Yup.string().required('Layout Type is required'), description: Yup.string() }); const { handleSubmit, errors, meta } = useForm({ validationSchema: schema, }); const { value: layoutName, errorMessage: layoutNameError } = useField("layoutName"); const { value: moduleId, errorMessage: moduleIdError } = useField("moduleId"); const { value: subModuleId, errorMessage: subModuleIdError } = useField("subModuleId"); const { value: deviceTypeId, errorMessage: deviceTypeIdError } = useField("deviceTypeId"); const { value: layoutTypeId, errorMessage: layoutTypeIdError } = useField("layoutTypeId"); const { value: description, errorMessage: descriptionError } = useField("description"); const getMasterItemList = (masterKey) => { // $loader.show(); commonService.value.getMasterItemList(masterKey, "asd", userId.value, companyId.value) .then(response => { masterKey == "layoutType" ? layoutTypeList.value = response.data : deviceTypeList.value = response.data; // $loader.hide(); }); } const getModuleList = () => { // $loader.show(); commonService.value.getModuleList(userId.value, companyId.value) .then(response => { moduleList.value = response.data; // $loader.hide(); }) } const getSubModuleList = (moduleId) => { // $loader.show(); commonService.value.getSubModuleList(moduleId, userId.value, companyId.value) .then(response => { subModuleList.value = response.data; // $loader.hide(); }) } const onChangeModule = (event) => { getSubModuleList(event.value); } const getUserInfo = () => { userId.value = localStorage.getItem("userId"); companyId.value = localStorage.getItem("companyId"); } const onSubmit = handleSubmit((values) => { debugger; console.log(JSON.stringify(values, null, 2)); }); onMounted(() => { getUserInfo(); getModuleList(); getMasterItemList(layoutTypeKey.value); getMasterItemList(deviceTypeKey.value); }) return { layoutObj, deviceTypeList, layoutTypeList, moduleList, subModuleList, errors, meta, layoutName, layoutNameError, moduleId, moduleIdError, subModuleId, subModuleIdError, deviceTypeId, deviceTypeIdError, layoutTypeId, layoutTypeIdError, description, descriptionError, getMasterItemList, getModuleList, onChangeModule, onSubmit } } } </script>
问题分析与解决
1. 修正Prop类型定义错误
你的props中用Yup.boolean定义isModalOpen的类型是错误的,Vue的Prop类型需要使用Vue内置的类型(如Boolean),而非Yup的验证方法。这个错误会导致组件初始化异常,进而影响handleSubmit的绑定。
修改后的props代码:
props: { isModalOpen: { type: Boolean, required: true // 根据需求设置是否必填 } }
2. 确保VeeValidate全局注册正确
检查项目的入口文件(如main.js)是否正确注册了VeeValidate核心组件与规则:
import { createApp } from 'vue'; import App from './App.vue'; import { Field, Form, ErrorMessage, defineRule, configure } from 'vee-validate'; import { required } from '@vee-validate/rules'; // 注册必填规则 defineRule('required', required); // 配置实时验证 configure({ validateOnInput: true, }); const app = createApp(App); // 全局注册VeeValidate组件 app.component('Field', Field); app.component('Form', Form); app.component('ErrorMessage', ErrorMessage); app.mount('#app');
3. 确认表单提交事件未被阻止
可以在onSubmit中添加调试日志,同时手动控制提交状态,确认事件是否触发:
const onSubmit = handleSubmit((values, actions) => { actions.setSubmitting(false); // 手动结束提交状态 console.log('表单提交触发,数据:', values); // 后续业务逻辑 });
4. 验证表单预验证状态
如果表单存在未通过验证的字段,handleSubmit会自动阻止进入回调函数。可以在模板中添加全局错误提示,确认是否是验证导致的提交失败:
<div v-if="meta.invalid" class="text-danger mb-3">表单存在错误,请检查后提交</div>
5. 检查PrimeVue组件的字段绑定一致性
确保PrimeVue的Dropdown组件的name属性与useField声明的字段名完全一致,同时确认组件的v-model正确绑定了useField返回的value值。
内容的提问来源于stack exchange,提问作者Fahad Ejaz Butt
相关产品推荐
相关产品推荐

