你有没有算过,过去一年你写了多少个表单?
Input + Select + DatePicker,组合、联动、校验、提交。80% 的代码结构几乎一样,但每次都要复制粘贴,改字段名,调布局,测联动。产品经理说”加两个字段”,你默默打开三个文件,修改几十行代码,再测试各种边界情况。
这些重复劳动的本质,不是表单太复杂,而是我们还在用”手工雕版”的方式做开发。
一个古老的类比
北宋毕昇发明活字印刷术之前,印一本书需要先把整页内容刻在木板上。想改一个字?整块木板作废,重新雕刻。
今天的表单开发,像极了这种”雕版印刷”:
- 字段定义和表单布局写在同一份 JSX 里,耦合在一起
- 每个表单都是一份独立的”雕版”,无法复用
- 需求变更等于”改字重刻”,牵一发而动全身
活字印刷的思路是:把每个字做成独立的字模,排版时按需组合,印完可复用。
配置驱动架构(Configuration-Driven Architecture)做的正是这件事:把”字”(字段)和”版”(表单)分开。
什么是配置驱动架构
简单说,就是把原本硬编码在代码里的逻辑,抽出来变成可维护的配置。
不是新概念。Webpack 用配置文件管理构建,Terraform 用 HCL 管理基础设施,很多系统都在这么做。但在前端表单领域,这个概念被贯彻得还不够彻底。
传统的表单开发:
const FormPage = () => {
const [name, setName] = useState('');
const [type, setType] = useState('');
// ... 还有28个
return (
<Form>
<Form.Item label="名称" required>
<Input value={name} onChange={setName} />
</Form.Item>
<Form.Item label="类型">
<Select value={type} onChange={setType} options={options} />
</Form.Item>
{/* 重复30次 */}
</Form>
);
};
配置驱动的思路:字段长什么样、怎么校验、怎么联动,全部用 JSON 描述。代码只负责读配置、渲染界面。
const fields = {
name: { label: '名称', component: 'Input', required: true },
type: { label: '类型', component: 'Select', options },
};
const config = {
sections: [{ fields: ['name', 'type'] }],
};
// 渲染引擎读取配置,自动生成表单
<FormEngine fields={fields} config={config} />
界面是配置的执行结果,不是代码的堆砌。
MovableType:一个具体的实现
如果你认同这个方向,可以看看 MovableType。它是一个基于 React 和 Ant Design 的纯渲染型配置引擎,命名就来自活字印刷术。
它的设计很克制,核心只有三个概念:
| 概念 | 作用 | 类比 |
|---|---|---|
| 字段池 (fields) | 定义所有可用字段的标签、组件、校验规则 | 字模仓库 |
| 表单配置 (config) | 决定某张表单用哪些字段、如何分组、何种布局 | 排版方案 |
| 组件注册表 | 自定义组件的加载方式,扩展引擎能力 | 特殊字体 |
字段池只管”字模长什么样”,配置只管”这次怎么排版”。同一份字段池可以被 N 个表单复用。需求变更时,改几行 JSON,而不是几十个组件文件。
它能做什么
1. 声明式联动,无需手写 useEffect
配置里写一句 watch,字段间联动自动处理:
{
name: 'city',
watch: {
province: (province, { form }) => {
form.setFieldsValue({ city: undefined });
return { dataLoader: `/api/cities?province=${province}` };
}
}
}
省份变化后,城市字段自动清空并加载新选项。不需要 useEffect,不需要手动处理 loading。
2. 一套配置,两种模式
通过 mode="edit" 或 mode="view" 切换。查看模式下,输入框自动变成纯文本展示,内置组件自动把 value 翻译成 label。不用写两份代码。
3. 为 AI 而生
这是最有意思的一点。因为整个表单被抽象为纯粹的结构化数据,大语言模型可以极低成本地生成、理解和修改这些配置。你不是在让 AI 写 React 组件,而是在让 AI 写 JSON——这恰恰是它最擅长的事。
效果对比
| 维度 | 传统开发 | 配置驱动 |
|---|---|---|
| 30字段表单代码量 | ~1000行 | ~230行(配置+引擎) |
| 新增一个字段 | 改多个 JSX 文件 | 加一行配置 |
| 修改验证规则 | 找到组件,改代码 | 改配置里的 rules |
| 查看模式 | 重写一份展示组件 | 切换 mode |
| AI 生成可行性 | 低(需理解组件上下文) | 高(纯结构化数据) |
背后的认知
配置驱动架构不是让你写更多 JSON,而是逼你做一件事:把数据和表现分开。
字段池是”数据”,表单配置是”排版方案”。两者解耦后,表单逻辑才变得高度结构化、可序列化、可复用。
这和 Form-Driven Architecture 是相通的:让专门的工具做专门的事。Form 管理表单状态,配置引擎管理表单结构,开发者只处理业务逻辑。
什么时候用
✅ 字段超过10个、多表单复用相同字段、需求变更频繁、需要AI辅助生成表单
❌ 2-3个字段的一次性表单(不值得引入引擎)
总结
从手工雕版到活字印刷,本质上是一次”分离关注”的胜利:字是字,版是版,各管各的。
配置驱动架构在做同样的事:字段定义一次,表单配置百次复用。需求变更时,改配置而不是改代码。
如果你想深入了解这个思路的具体实现,包括声明式联动的完整语法、自定义组件的扩展方式、以及如何让 AI 帮你生成配置,可以去看 MovableType 的完整文档。
技术的选择,往往取决于你愿不愿意承认一件事:很多重复劳动,本来就不该存在。