系列文档目录
Vue3+Vite+TypeScript安装
Element Plus安装与配置
主页设计与router配置
静态菜单设计
Pinia引入
Header响应式菜单缩展
Mockjs引用与Axios封装
登录设计
登录成功跳转主页
多用户动态加载菜单
Pinia持久化
动态路由 -动态增加路由
动态路由-动态删除路由
路由守卫-无路由跳转404
路由守卫-未登录跳转登录界面
登录退出
Tags-组件构建
Tags-与菜单联动
Pinia持久化优化
按钮权限
客制按钮组件
客制Table组件
客制Form组件
国际化
配置文件
文章目录
目录
系列文档目录
文章目录
前言
子组件-Form组件构建
父组件-Form组件调用
演示效果
编辑
模拟测试
父组件-Form组件多界面
后续
代码下载
前言
在实际项目开发中,表单(Form)的数据编辑功能是常见需求。为了提高开发效率,本章节将重点介绍如何对表单组件进行封装,从而实现快速开发。
子组件-Form组件构建
创建文件: components/ActionFormCont.vue
实现功能:
1. 栏位定义: 控件配置由父组件传入,控件可自定义隐藏。
2. 数据来源: 控件数据由父组件提供。
3. 帅选功能: 数据选择由父组件提供。
4. 数据检证: 数据验证由父组件提供。
<template><el-formref="formRef":model="formData"label-width="120px":rules="rules"class="form"><div v-for="item in fields" :key="item.prop"><el-form-itemv-if="!item.hide":label="item.label":prop="item.prop":rules="item.rules"><el-inputv-if="item.InputType === 'text'"v-model="formData[item.prop]":disabled="item.ReadOnly":placeholder="`请输入${item.label}`"></el-input><el-selectv-else-if="item.InputType === 'select'"v-model="formData[item.prop]":disabled="item.ReadOnly"placeholder="请选择"><el-optionv-for="option in item.options":key="option.value":label="option.label":value="option.value"></el-option></el-select><el-date-pickerv-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-dialogv-model="dialogVisible"title="表单操作"width="50%":before-close="handleClose"><FormComponentref="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-dialogv-model="dialogVisible"title="表单操作"width="50%":before-close="handleClose"><FormComponentref="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-dialogv-model="detailDialogVisible"title="明细新增"width="50%":before-close="handleDetailClose"><FormComponentref="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