系列文档目录
国际化
文章目录
目录
前言
在实际项目开发中,表单(Form)的数据编辑功能是常见需求。为了提高开发效率,本章节将重点介绍如何对表单组件进行封装,从而实现快速开发。
子组件-Form组件构建
创建文件: components/ActionFormCont.vue
实现功能:
1. 栏位定义: 控件配置由父组件传入,控件可自定义隐藏。
2. 数据来源: 控件数据由父组件提供。
3. 帅选功能: 数据选择由父组件提供。
4. 数据检证: 数据验证由父组件提供。
<template>
<el-form
ref="formRef"
:model="formData"
label-width="120px"
:rules="rules"
class="form"
>
<div v-for="item in fields" :key="item.prop">
<el-form-item
v-if="!item.hide"
:label="item.label"
:prop="item.prop"
:rules="item.rules"
>
<el-input
v-if="item.InputType === 'text'"
v-model="formData[item.prop]"
:disabled="item.ReadOnly"
:placeholder="`请输入${item.label}`"
></el-input>
<el-select
v-else-if="item.InputType === 'select'"
v-model="formData[item.prop]"
:disabled="item.ReadOnly"
placeholder="请选择"
>
<el-option
v-for="option in item.options"
:key="option.value"
:label="option.label"
:value="option.value"
></el-option>
</el-select>
<el-date-picker
v-else-if="item.InputType === 'date'"
v-model="formData[item.prop]"
:disabled="item.ReadOnly"
type="date"
placeholder="选择日期"
@change="formatDate(item.prop, $event)"
></el-date-picker>
</el-form-item>
</div>
</el-form>
</template>
<script lang="ts" setup>
import { ref, watch, PropType, defineEmits } from "vue";
import type { FormInstance } from "element-plus";
interface Field {
prop: string;
label: string;
width?: number;
hide?: boolean;
ReadOnly?: boolean;
InputType: "text" | "select" | "date";
IsNull?: boolean;
Validation?: any; // 校验规则
options?: { label: string; value: any }[];
}
const props = defineProps({
fields: {
type: Array as PropType<Field[]>,
required: true,
},
data: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(["update:data"]);
const formRef = ref<FormInstance | null>(null);
const formData = ref({ ...props.data });
watch(() => props.data, (newValue) => {
formData.value = { ...newValue };
}, { deep: true });
watch(formData, (newValue) => {
emit("update:data", newValue);
}, { deep: true });
const rules = props.fields.reduce((acc, field) => {
acc[field.prop] = [];
if (!field.IsNull) {
acc[field.prop].push({
required: true,
message: `${field.label}不能为空`,
trigger: "blur",
});
}
if (field.Validation) {
acc[field.prop].push(field.Validation);
}
return acc;
}, {} as Record<string, any>);
const formatDate = (prop: string, date: Date) => {
if (date) {
formData.value[prop] = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
} else {
formData.value[prop] = '';
}
};
</script>
<style scoped>
.form {
max-width: 600px;
margin: 0 auto;
}
</style>
父组件-Form组件调用
组件控件定义:
姓名:增加数据验证
性别:有下选框
const fields = ref([
{
prop: "name",
label: "姓名",
width: 200,
hide: false,
ReadOnly: false,
InputType: "text",
IsNull: false,
Validation: {
validator: nameValidator,
trigger: "blur",
},
},
{
prop: "age",
label: "年龄",
width: 200,
hide: false,
ReadOnly: false,
InputType: "text",
IsNull: true,
},
{
prop: "gender",
label: "性别",
width: 200,
hide: false,
ReadOnly: false,
InputType: "select",
options: [
{ label: "男", value: "male" },
{ label: "女", value: "female" },
],
IsNull: false,
},
{
prop: "birthDate",
label: "出生日期",
width: 200,
hide: false,
ReadOnly: false,
InputType: "date",
IsNull: true,
},
]);
const handleAdd = () => {
formData.value = {
name: "默认姓名",
};
dialogVisible.value = true;
};
完整代码:
<template>
<div>
<el-button type="primary" @click="handleAdd">新增</el-button>
<el-button type="success" @click="handleEdit">编辑</el-button>
<el-dialog
v-model="dialogVisible"
title="表单操作"
width="50%"
:before-close="handleClose"
>
<FormComponent
ref="formComponentRef"
:fields="fields"
v-model:data="formData"
@update:data="handleFormDataUpdate"
></FormComponent>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import FormComponent from "@/components/FormComponent.vue";
const formComponentRef = ref(null);
const formData = ref({});
const dialogVisible = ref(false);
const nameValidator = (rule: any, value: any, callback: any) => {
if (value && value.length < 3) {
callback(new Error("姓名长度不能小于3"));
} else {
callback();
}
};
const fields = ref([
{
prop: "name",
label: "姓名",
width: 200,
hide: false,
ReadOnly: false,
InputType: "text",
IsNull: false,
Validation: {
validator: nameValidator,
trigger: "blur",
},
},
{
prop: "age",
label: "年龄",
width: 200,
hide: false,
ReadOnly: false,
InputType: "text",
IsNull: true,
},
{
prop: "gender",
label: "性别",
width: 200,
hide: false,
ReadOnly: false,
InputType: "select",
options: [
{ label: "男", value: "male" },
{ label: "女", value: "female" },
],
IsNull: false,
},
{
prop: "birthDate",
label: "出生日期",
width: 200,
hide: false,
ReadOnly: false,
InputType: "date",
IsNull: true,
},
]);
const handleAdd = () => {
formData.value = {
name: "默认姓名",
};
dialogVisible.value = true;
};
const handleEdit = () => {
formData.value = {
name: "张三",
age: "25",
gender: "male",
birthDate: "2025-04-09",
};
dialogVisible.value = true;
};
const handleSave = () => {
(formComponentRef.value as any).$refs.formRef.validate((valid: boolean, errors: any) => {
if (valid) {
// 获取最新的表单数据
const latestFormData = { ...formData.value };
console.log("保存的数据:", latestFormData);
alert("保存成功");
dialogVisible.value = false;
} else {
// 获取具体的错误信息
const errorMessages = Object.values(errors).map((error: any) => error.message).join("\n");
alert(`表单校验失败:\n${errorMessages}`);
}
});
};
const handleCancel = () => {
dialogVisible.value = false;
};
const handleClose = (done: () => void) => {
dialogVisible.value = false;
done();
};
const handleFormDataUpdate = (newData: any) => {
formData.value = { ...newData };
};
</script>
说明:该功能演示按钮未引用自定义组件
功能说明:
• 新增:新增时自动填充默认值,其余字段保持空白。
• 编辑:加载全部数据进行编辑。
• 保存:进行数据验证(包括长度检查和非空校验),若验证通过则保存数据。
• 取消:关闭当前窗口。
演示效果
模拟测试
保存时,获取资料正确。
验证测试已通过,此处暂不提供截图
父组件-Form组件多界面
在原有功能基础上,新增一个“新增明细”按钮,点击后可实现明细数据的新增操作。
<template>
<div>
<el-button type="primary" @click="handleAdd">新增</el-button>
<el-button type="success" @click="handleEdit">编辑</el-button>
<el-button type="info" @click="handleDetailAdd">明细新增</el-button>
<el-dialog
v-model="dialogVisible"
title="表单操作"
width="50%"
:before-close="handleClose"
>
<FormComponent
ref="formComponentRef"
:fields="fields"
v-model:data="formData"
@update:data="handleFormDataUpdate"
></FormComponent>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</span>
</template>
</el-dialog>
<el-dialog
v-model="detailDialogVisible"
title="明细新增"
width="50%"
:before-close="handleDetailClose"
>
<FormComponent
ref="detailFormComponentRef"
:fields="detailFields"
v-model:data="detailFormData"
@update:data="handleDetailFormDataUpdate"
></FormComponent>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleDetailCancel">取消</el-button>
<el-button type="primary" @click="handleDetailSave">保存</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import FormComponent from "@/components/ActionFormCont.vue";
const formComponentRef = ref(null);
const detailFormComponentRef = ref(null);
const formData = ref({});
const detailFormData = ref({});
const dialogVisible = ref(false);
const detailDialogVisible = ref(false);
// 主表单的校验函数
const nameValidator = (rule: any, value: any, callback: any) => {
if (value && value.length < 3) {
callback(new Error("姓名长度不能小于3"));
} else {
callback();
}
};
// 明细表单的校验函数
const detailNameValidator = (rule: any, value: any, callback: any) => {
if (value && value.length < 3) {
callback(new Error("明细名称长度不能小于3"));
} else {
callback();
}
};
const fields = ref([
{
prop: "name",
label: "姓名",
width: 200,
hide: false,
ReadOnly: false,
InputType: "text",
IsNull: false,
Validation: {
validator: nameValidator,
trigger: "blur",
},
},
{
prop: "age",
label: "年龄",
width: 200,
hide: false,
ReadOnly: false,
InputType: "text",
IsNull: true,
},
{
prop: "gender",
label: "性别",
width: 200,
hide: false,
ReadOnly: false,
InputType: "select",
options: [
{ label: "男", value: "male" },
{ label: "女", value: "female" },
],
IsNull: false,
},
{
prop: "birthDate",
label: "出生日期",
width: 200,
hide: false,
ReadOnly: false,
InputType: "date",
IsNull: true,
},
]);
const detailFields = ref([
{
prop: "detailName",
label: "明细名称",
width: 200,
hide: false,
ReadOnly: false,
InputType: "text",
IsNull: false,
Validation: {
validator: detailNameValidator,
trigger: "blur",
},
},
{
prop: "detailAmount",
label: "明细金额",
width: 200,
hide: false,
ReadOnly: false,
InputType: "text",
IsNull: true,
},
]);
const handleAdd = () => {
formData.value = {
name: "默认姓名",
age: "",
gender: "",
birthDate: "",
};
dialogVisible.value = true;
};
const handleEdit = () => {
formData.value = {
name: "张三",
age: "25",
gender: "male",
birthDate: "2025-04-09",
};
dialogVisible.value = true;
};
const handleDetailAdd = () => {
detailFormData.value = {
detailName: "默认明细名称",
detailAmount: "100",
};
detailDialogVisible.value = true;
};
const handleSave = () => {
(formComponentRef.value as any).$refs.formRef.validate((valid: boolean, errors: any) => {
if (valid) {
const latestFormData = { ...formData.value };
console.log("保存的数据:", latestFormData);
alert("保存成功");
dialogVisible.value = false;
} else {
const errorMessages = Object.values(errors).map((error: any) => error.message).join("\n");
alert(`表单校验失败:\n${errorMessages}`);
}
});
};
const handleDetailSave = () => {
(detailFormComponentRef.value as any).$refs.formRef.validate((valid: boolean, errors: any) => {
if (valid) {
const latestDetailFormData = { ...detailFormData.value };
console.log("明细保存的数据:", latestDetailFormData);
alert("明细保存成功");
detailDialogVisible.value = false;
} else {
const errorMessages = Object.values(errors).map((error: any) => error.message).join("\n");
alert(`明细表单校验失败:\n${errorMessages}`);
}
});
};
const handleCancel = () => {
dialogVisible.value = false;
};
const handleDetailCancel = () => {
detailDialogVisible.value = false;
};
const handleClose = (done: () => void) => {
dialogVisible.value = false;
done();
};
const handleDetailClose = (done: () => void) => {
detailDialogVisible.value = false;
done();
};
const handleFormDataUpdate = (newData: any) => {
formData.value = { ...newData };
};
const handleDetailFormDataUpdate = (newData: any) => {
detailFormData.value = { ...newData };
};
</script>
多界面演示
后续
下一章讲解国际化
代码下载
GitCode - 全球开发者的开源社区,开源代码托管平台GitCode是面向全球开发者的开源社区,包括原创博客,开源代码托管,代码协作,项目管理等。与开发者社区互动,提升您的研发效率和质量。https://gitcode.com/sen_shan/ssVue3Demo.gitss.vue3.demo: 本项目以 Vue3、Vite、TypeScript、Element Plus 为核心框架,结合 Vue Router、Element Plus Icons、Less、Axios、Pinia、Mock 等技术,初始的构建登录,主界面,权限控制,按钮组件,table组件,form组件等小模型,可以随意搭建web管理系统
https://gitee.com/sen_shan/ssVue3Demo.git