各位掘友好,我是庚云。还在为重复写表单而头疼?学会这招,后端配置自动生成,效率提升300%!前端必备技能!
下面将提供 Vue + React 两个版本的具体实现,感觉有用的点赞收藏。
✨ 本文亮点
✅ 配置即页面 - 后端返回配置,前端自动渲染
✅ 智能条件显示 - 字段联动,动态显隐
✅ 强大校验系统 - 必填验证+自定义规则+远程校验
✅ 极致性能优化 - computed + 动态组件,减少重复渲染
✅ 完整实战代码 - 即拷即用,轻松上手
🎯 适用场景
- 低代码平台表单构建
- 动态问卷系统
- 可配置化管理后台
- 需要频繁变更的表单业务
一、React版本
功能说明
✅ 后端驱动:从接口获取表单配置
✅ 字段类型支持:文本框、下拉框、日期选择、复选框
✅ 动态增删:可添加、删除字段
✅ 数据校验:必填、格式校验
✅ 实时数据预览:表单数据展示
完整React代码
import React, { useState, useEffect } from "react";
import { Form, Input, Select, DatePicker, Checkbox, Button } from "antd";
import { PlusOutlined, MinusCircleOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
const fetchFormConfig = async () => {
return [
{ label: "姓名", type: "input", key: "name", required: true },
{ label: "性别", type: "select", key: "gender", options: ["男", "女"] },
{ label: "出生日期", type: "date", key: "birthDate" },
{ label: "爱好", type: "checkbox", key: "hobbies", options: ["阅读", "旅行", "运动"] },
{ label: "职业", type: "select", key: "job", options: ["工程师", "设计师", "教师"] },
{ label: "公司名称", type: "input", key: "company", dependsOn: "job", validation: (value, form) => !!form.getFieldValue("job") || "请先选择职业" },
{ label: "工作年限", type: "input", key: "experience", dependsOn: "job", validation: (value) => (Number(value) > 0 && Number(value) <= 50) || "工作年限必须在 1-50 之间" },
];
};
const fetchRemoteOptions = async () => {
return ["工程师", "设计师", "教师", "医生", "律师"];
};
const LowCodeForm = () => {
const [formConfig, setFormConfig] = useState([]);
const [jobOptions, setJobOptions] = useState([]);
const [form] = Form.useForm();
const job = Form.useWatch("job", form);
useEffect(() => {
fetchFormConfig().then(setFormConfig);
fetchRemoteOptions().then(setJobOptions);
}, []);
return (
<div style={{ maxWidth: 600, margin: "0 auto" }}>
<Form form={form} layout="vertical">
{formConfig.map(({ label, type, key, options, required, dependsOn, validation }) => (
(!dependsOn || (dependsOn && form.getFieldValue(dependsOn))) && (
<Form.Item
key={key}
label={label}
name={key}
rules={[{ required, message: `${label} 必填` }, validation && { validator: (_, value) => validation(value, form) ? Promise.resolve() : Promise.reject(validation(value, form)) }].filter(Boolean)}
>
{type === "input" && <Input placeholder={`请输入${label}`} />}
{type === "select" && (
<Select
options={(key === "job" ? jobOptions : options).map(o => ({ value: o, label: o }))}
placeholder="请选择"
/>
)}
{type === "date" && <DatePicker style={{ width: "100%" }} />}
{type === "checkbox" && <Checkbox.Group options={options} />}
</Form.Item>
)
))}
{/* 动态字段 */}
<Form.List name="experiences">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name }) => (
<Form.Item key={key} label={`工作经历 ${name + 1}`}>
<Input placeholder="请输入工作经历" style={{ width: "80%" }} />
<MinusCircleOutlined onClick={() => remove(name)} style={{ marginLeft: 8 }} />
</Form.Item>
))}
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>添加工作经历</Button>
</>
)}
</Form.List>
<Button type="primary" onClick={() => console.log(form.getFieldsValue())}>提交</Button>
</Form>
</div>
);
};
export default LowCodeForm;
功能细节
-
后端驱动:
fetchFormConfig模拟后端 API 获取表单配置。 -
动态渲染:遍历
formConfig生成输入框、下拉框、日期选择等。 -
支持动态增删字段:可以动态添加/删除“工作经历”字段。
-
数据提交:点击“提交”按钮,在控制台打印当前表单数据。
✅ 联动逻辑: "公司名称" 字段仅在选择了 "职业" 后显示。
✅ 远程数据源: "职业" 选项从远程接口 fetchRemoteOptions 获取,而不是写死在前端。
✅ 复杂校验: 必填校验:如果字段 required: true,则必须填写,否则报错。
✅ 动态校验规则:
- "公司名称" 只有在选择了 "职业" 后才能填写,否则报错。
- "工作年限" 需在 1-50 年之间,否则提示错误。
✅ 条件字段控制: "公司名称" 和 "工作年限" 只有在选择职业后才会显示。
✅ 数据联动计算(可扩展): 目前的规则基础上,可以进一步添加动态计算字段,比如:根据工作年限自动计算退休年龄。
二、Vue版本
功能说明
✅ 动态校验规则(如工作年限限制)
✅ 条件字段控制(如选择职业后才显示公司名称)
✅ 数据联动计算(如动态获取职业选项)
✅ 动态字段管理(如添加/删除工作经历)
Vue3低代码动态表单Demo
<template>
<div style="max-width: 600px; margin: auto;">
<el-form :model="form" label-width="100px" ref="formRef">
<template v-for="item in filteredFormConfig" :key="item.key">
<el-form-item :label="item.label" :prop="item.key" :rules="getValidationRules(item)">
<el-input v-if="item.type === 'input'" v-model="form[item.key]" :placeholder="`请输入${item.label}`" />
<el-select v-else-if="item.type === 'select'" v-model="form[item.key]" placeholder="请选择">
<el-option v-for="option in (item.key === 'job' ? jobOptions : item.options)" :key="option" :label="option" :value="option" />
</el-select>
<el-date-picker v-else-if="item.type === 'date'" v-model="form[item.key]" type="date" style="width: 100%;" />
<el-checkbox-group v-else-if="item.type === 'checkbox'" v-model="form[item.key]">
<el-checkbox v-for="option in item.options" :key="option" :label="option" />
</el-checkbox-group>
</el-form-item>
</template>
<!-- 动态字段 -->
<el-form-item label="工作经历">
<div v-for="(exp, index) in form.experiences" :key="index" style="display: flex; align-items: center;">
<el-input v-model="form.experiences[index]" placeholder="请输入工作经历" style="width: 80%;" />
<el-button type="danger" icon="el-icon-minus" @click="removeExperience(index)" />
</div>
<el-button type="dashed" icon="el-icon-plus" @click="addExperience">添加工作经历</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
const formRef = ref(null);
const form = ref({ experiences: [] });
const jobOptions = ref([]);
const formConfig = ref([]);
const fetchFormConfig = async () => {
return [
{ label: "姓名", type: "input", key: "name", required: true },
{ label: "性别", type: "select", key: "gender", options: ["男", "女"] },
{ label: "出生日期", type: "date", key: "birthDate" },
{ label: "爱好", type: "checkbox", key: "hobbies", options: ["阅读", "旅行", "运动"] },
{ label: "职业", type: "select", key: "job", options: [] },
{ label: "公司名称", type: "input", key: "company", dependsOn: "job" },
{ label: "工作年限", type: "input", key: "experience", dependsOn: "job", validation: (value) => Number(value) > 0 && Number(value) <= 50 || "工作年限必须在 1-50 之间" },
];
};
const fetchRemoteOptions = async () => {
return ["工程师", "设计师", "教师", "医生", "律师"];
};
onMounted(async () => {
formConfig.value = await fetchFormConfig();
jobOptions.value = await fetchRemoteOptions();
});
const filteredFormConfig = computed(() => {
return formConfig.value.filter(item => !item.dependsOn || form.value[item.dependsOn]);
});
const getValidationRules = (item) => {
const rules = [];
if (item.required) {
rules.push({ required: true, message: `${item.label} 必填` });
}
if (item.validation) {
rules.push({ validator: (_, value, callback) => {
if (item.validation(value)) {
callback();
} else {
callback(new Error(item.validation(value)));
}
}});
}
return rules;
};
const addExperience = () => {
form.value.experiences.push('');
};
const removeExperience = (index) => {
form.value.experiences.splice(index, 1);
};
const submitForm = async () => {
try {
await formRef.value.validate();
console.log(form.value);
ElMessage.success("提交成功!");
} catch (error) {
ElMessage.error("请完善表单信息");
}
};
</script>
<style scoped>
.el-button {
margin-top: 10px;
}
</style>
Vue优化版本
优化 Vue3 代码,采用 computed 计算字段显示,并 使用动态组件 来减少 if 判断。
✅ 逻辑更清晰
✅ 易扩展,可自由增删字段
<template>
<div style="max-width: 600px; margin: auto;">
<el-form :model="form" label-width="100px" ref="formRef">
<el-form-item v-for="item in visibleFields" :key="item.key" :label="item.label" :prop="item.key" :rules="getValidationRules(item)">
<component :is="fieldTypes[item.type]" v-model="form[item.key]" v-bind="item.props">
<el-option v-for="option in getOptions(item)" :key="option" :label="option" :value="option" />
</component>
</el-form-item>
<!-- 动态字段 -->
<el-form-item label="工作经历">
<div v-for="(exp, index) in form.experiences" :key="index" style="display: flex; align-items: center;">
<el-input v-model="form.experiences[index]" placeholder="请输入工作经历" style="width: 80%;" />
<el-button type="danger" icon="el-icon-minus" @click="removeExperience(index)" />
</div>
<el-button type="dashed" icon="el-icon-plus" @click="addExperience">添加工作经历</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
const formRef = ref(null);
const form = ref({ experiences: [] });
const jobOptions = ref([]);
const formConfig = ref([]);
const fieldTypes = {
input: "el-input",
select: "el-select",
date: "el-date-picker",
checkbox: "el-checkbox-group",
};
const fetchFormConfig = async () => {
return [
{ label: "姓名", type: "input", key: "name", required: true },
{ label: "性别", type: "select", key: "gender", options: ["男", "女"] },
{ label: "出生日期", type: "date", key: "birthDate" },
{ label: "爱好", type: "checkbox", key: "hobbies", options: ["阅读", "旅行", "运动"] },
{ label: "职业", type: "select", key: "job", options: [] },
{ label: "公司名称", type: "input", key: "company", dependsOn: "job" },
{ label: "工作年限", type: "input", key: "experience", dependsOn: "job", validation: (value) => Number(value) > 0 && Number(value) <= 50 || "工作年限必须在 1-50 之间" },
];
};
const fetchRemoteOptions = async () => {
return ["工程师", "设计师", "教师", "医生", "律师"];
};
onMounted(async () => {
formConfig.value = await fetchFormConfig();
jobOptions.value = await fetchRemoteOptions();
});
const visibleFields = computed(() => {
return formConfig.value.filter(item => !item.dependsOn || form.value[item.dependsOn]);
});
const getValidationRules = (item) => {
const rules = [];
if (item.required) {
rules.push({ required: true, message: `${item.label} 必填` });
}
if (item.validation) {
rules.push({ validator: (_, value, callback) => {
if (item.validation(value)) {
callback();
} else {
callback(new Error(item.validation(value)));
}
}});
}
return rules;
};
const getOptions = (item) => {
return item.key === "job" ? jobOptions.value : item.options;
};
const addExperience = () => {
form.value.experiences.push('');
};
const removeExperience = (index) => {
form.value.experiences.splice(index, 1);
};
const submitForm = async () => {
try {
await formRef.value.validate();
console.log(form.value);
ElMessage.success("提交成功!");
} catch (error) {
ElMessage.error("请完善表单信息");
}
};
</script>
<style scoped>
.el-button {
margin-top: 10px;
}
</style>