我正在为我的作品集编写一个个人项目。 我正在制作一个注册网站。
因此用户将填写:个人数据、运输信息,然后将看到回顾。
我有一个视图(Register.vue),我在其中放置了 Vuetify 的步进器以使速度更快。
共有三个步骤:PersonalDataForm(一个单独的组件)、ShippingForm(另一个单独的组件)和回顾。
因此,对于每一步,用户都可以填写表格,然后继续下一步。
我面临的问题是:
注册查看
<template>
<v-stepper color="deep-purple-darken-1" :items="['Dati Anagrafici', 'Indirizzo di spedizione', 'Riepilogo']" class="my-5">
<template v-slot:item.1>
<v-card>
<PersonalDataForm @formDataSubmitted="handlePersonalDataForm" :isFormIncomplete="personalDataFormIsIncomplete"/>
</v-card>
</template>
<template v-slot:item.2>
<v-card>
<ShippingForm @formDataSubmitted="handleShippingForm" :isFormIncomplete="shippingFormIsIncomplete"/>
</v-card>
</template>
<template v-slot:item.3>
<v-card>
<Recap @completed="submitData" :disabled="isFormIncomplete"/>
</v-card>
</template>
</v-stepper>
</template>
<script setup>
import { ref, computed } from 'vue';
import PersonalDataForm from '@/components/forms/PersonalDataForm.vue';
import ShippingForm from '@/components/forms/ShippingForm.vue';
import Recap from '../components/Recap.vue';
const personalDataFormIsIncomplete = ref(true);
const shippingFormIsIncomplete = ref(true);
const isFormIncomplete = computed(() => {
return personalDataFormIsIncomplete.value || shippingFormIsIncomplete.value;
});
const handlePersonalDataForm = (formData) => {
console.log("Received personal data:", formData);
personalDataFormIsIncomplete.value = false;
};
const handleShippingForm = (formData) => {
console.log("Received shipping data:", formData);
shippingFormIsIncomplete.value = false;
};
const submitData = () => {
console.log('Submitting data...');
};
</script>
```
PersonalDataForm.vue
```
<template>
<v-container>
<v-card class="rounded-lg py-4 px-8" elevation="8">
<form @submit.prevent="handleSubmit">
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="state.firstName"
:error-messages="v$.firstName.$errors.map((e) => e.$message)"
label="Nome"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.firstName.$touch"
@input="v$.firstName.$touch"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="state.lastName"
:error-messages="v$.lastName.$errors.map((e) => e.$message)"
label="Cognome"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.lastName.$touch"
@input="v$.lastName.$touch"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="state.birthDate"
:error-messages="v$.birthDate.$errors.map((e) => e.$message)"
type="date"
label="Data di Nascita"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.birthDate.$touch"
@input="v$.birthDate.$touch"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="state.birthPlace"
:error-messages="v$.birthPlace.$errors.map((e) => e.$message)"
label="Città di Nascita"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.birthPlace.$touch"
@input="v$.birthPlace.$touch"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="state.fiscalCode"
:error-messages="v$.fiscalCode.$errors.map((e) => e.$message)"
label="Codice Fiscale"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.fiscalCode.$touch"
@input="v$.fiscalCode.$touch"
></v-text-field>
</v-col>
</v-row>
<v-btn class="me-4" @click="handleSubmit"> submit </v-btn>
</form>
</v-card>
</v-container>
</template>
<script setup>
import { ref, computed } from 'vue';
import { useVuelidate } from "@vuelidate/core";
import { required } from "@vuelidate/validators";
const state = ref({
firstName: "",
lastName: "",
birthDate: "",
birthPlace: "",
fiscalCode: "",
});
const rules = {
firstName: { required },
lastName: { required },
birthDate: { required },
birthPlace: { required },
fiscalCode: { required }
};
const v$ = useVuelidate(rules, state.value);
const isFormIncomplete = computed(() => {
return Object.values(state.value).some(value => !value);
});
function handleSubmit() {
v$.value.$touch();
if (!v$.value.$invalid) {
// Form is valid, proceed with submitting data
const formData = { ...state.value };
console.log("Submitting form data:", formData);
// Here you can call your submit function or perform any necessary action
// Example: submitFormData(formData);
} else {
// Form is invalid, do something (e.g., show error message)
console.log("Form has validation errors, cannot submit.");
}
}
</script>
```
ShippingForm.vue
<template>
<v-container>
<v-card class="rounded-lg py-4 px-8" elevation="8">
<form @submit.prevent="handleSubmit">
<v-row>
<!-- fare che tipo sia precompilato e non modificabile -->
<v-col cols="12" md="6">
<v-text-field
v-model="state.firstName"
:error-messages="v$.firstName.$errors.map((e) => e.$message)"
label="Nome"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.firstName.$touch"
@input="v$.firstName.$touch"
></v-text-field>
</v-col>
<!-- fare che tipo sia precompilato e non modificabile -->
<v-col cols="12" md="6">
<v-text-field
v-model="state.lastName"
:error-messages="v$.lastName.$errors.map((e) => e.$message)"
label="Cognome"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.lastName.$touch"
@input="v$.lastName.$touch"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-select
v-model="state.region"
:items="regions"
:error-messages="v$.region.$errors.map((e) => e.$message)"
label="Regione"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.region.$touch"
@input="v$.region.$touch"
></v-select>
</v-col>
<v-col cols="12" md="6">
<v-select
v-model="state.province"
:items="provinces"
:error-messages="v$.province.$errors.map((e) => e.$message)"
label="Provincia"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.province.$touch"
@input="v$.province.$touch"
></v-select>
</v-col>
<v-col cols="12" md="6">
<v-select
v-model="state.city"
:items="cities"
:error-messages="v$.city.$errors.map((e) => e.$message)"
label="Città"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.city.$touch"
@input="v$.city.$touch"
></v-select>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="state.houseNumber"
:error-messages="v$.houseNumber.$errors.map((e) => e.$message)"
label="Civico"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.houseNumber.$touch"
@input="v$.houseNumber.$touch"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="state.email"
:error-messages="v$.email.$errors.map((e) => e.$message)"
label="E-mail"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.email.$touch"
@input="v$.email.$touch"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="state.phoneNumber"
:error-messages="v$.phoneNumber.$errors.map((e) => e.$message)"
label="Telefono"
required
variant="underlined"
color="deep-purple-lighten-1"
@blur="v$.phoneNumber.$touch"
@input="v$.phoneNumber.$touch"
></v-text-field>
</v-col>
</v-row>
<v-btn class="me-4" type="submit" @click="handleSubmit"> submit </v-btn>
</form>
</v-card>
</v-container>
</template>
<script setup>
import { reactive, computed, defineProps } from 'vue';
import { useVuelidate } from "@vuelidate/core";
import {
email,
required,
numeric,
minLength,
maxLength,
} from "@vuelidate/validators";
const props = defineProps(['formData']);
const emit = props['onUpdate:formData'];
const initialState = {
firstName: "",
lastName: "",
region: "",
province: "",
city: "",
houseNumber: "",
email: "",
phoneNumber: "",
};
const state = reactive({
...initialState,
});
const isFormIncomplete = computed(() => {
return Object.values(state).some(value => !value); // Check if any field is empty
});
const regions = ["Emilia", "Lombardia", "Calabria", "Piemonte"];
const provinces = ["piacenza", "Milano", "Cosenza", "Torino"];
const cities = ["Caorso", "Assago", "Lamezia", "Settimo Torinese"];
const rules = {
firstName: { required },
lastName: { required },
region: { required },
province: { required },
city: { required },
houseNumber: { required, numeric },
email: { required, email },
phoneNumber: {
required,
numeric,
minLength: minLength(12),
maxLength: maxLength(12),
},
};
const v$ = useVuelidate(rules, state);
const getData = computed(() => {
return {
firstName: state.firstName,
lastName: state.lastName,
region: state.region,
province: state.province,
city: state.city,
houseNumber: state.houseNumber,
email: state.email,
phoneNumber: state.phoneNumber,
};
});
function handleSubmit() {
v$.value.$touch();
emit('formDataSubmitted', formData.value);
if (!v$.value.$invalid) {
// Form is valid, proceed with submitting data
const formData = { ...state };
console.log("Submitting form data:", formData);
// Here you can call your submit function or perform any necessary action
// Example: submitFormData(formData);
} else {
// Form is invalid, do something (e.g., show error message)
console.log("Form has validation errors, cannot submit.");
}
}
</script>
`
简单的解决方案是为每种表单类型提供布尔标志。如果表单提交有效,则更新相应的布尔标志并显示/禁用下一个按钮。
您需要创建 formDataSubscribed 事件并在成功提交表单时发出此事件。在父组件中监听此事件并更新布尔标志。
<script setup>
const emit = defineEmits(['formDataSubmitted']);
function handleSubmit() {
...other code
if(formValid) {
emit('formDataSubmitted', formData);
}
}
</script>
在此处了解有关 Vue 中事件如何工作的更多信息:Vue 事件发射器