mzm-auto-form
v1.2.5
Published
基于vue3、element-plus、typeScript实现的数据驱动式动态表单组件
Maintainers
Readme
mzm-auto-form
基于 Vue3、Element-Plus、TypeScript 实现的数据驱动式动态表单组件。旨在通过 JSON 配置的方式快速构建复杂表单。
特性
- 🚀 数据驱动: 完全通过配置对象渲染表单,摆脱冗长的 HTML 模板。
- 📦 开箱即用: 内置丰富的表单控件类型(输入框、选择器、日期、开关、上传等)。
- 🔗 响应式联动: 支持基于
formData状态的动态显示/隐藏、动态禁用、动态校验规则与动态选项列表。 - 🎯 完美兼容 Element Plus: 继承
el-form及内部控件的所有属性与事件,支持插槽注入。 - 🤖 大模型友好 (LLM-Friendly): 提供了清晰的 TypeScript 接口定义,方便在通过 AI 生成代码时保持严格的类型约束。
安装
npm i mzm-auto-form引入
1. 全局注册 (main.ts)
import { createApp } from "vue";
import App from "./App.vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import MzmAutoForm from "mzm-auto-form";
import "mzm-auto-form/lib/index.css";
const app = createApp(App);
app.use(ElementPlus);
app.use(MzmAutoForm);
app.mount("#app");2. 局部引入 (在组件中)
import { mzmAutoForm } from "mzm-auto-form";
import "mzm-auto-form/lib/index.css";基础用法
通过定义 configList 数组即可快速渲染表单:
<template>
<mzm-auto-form
ref="formRef"
:config-list="formConfig"
label-width="120px"
@loaded="handleLoaded"
>
<!-- 自定义插槽内容 -->
<template #customSlot="{ formData, formItem }">
<el-button @click="formData[formItem.key] = 'custom'">
自定义按钮:{{ formData[formItem.key] }}
</el-button>
</template>
</mzm-auto-form>
<el-button
type="primary"
@click="submit"
>提交</el-button
>
</template>
<script setup lang="ts">
import { ref } from "vue";
import {
mzmAutoForm,
AutoFormItemType,
type AutoFormItem,
} from "mzm-auto-form";
import "mzm-auto-form/lib/index.css";
const formRef = ref<InstanceType<typeof mzmAutoForm>>();
const formConfig = ref<AutoFormItem[]>([
{
key: "username",
type: AutoFormItemType.Input,
formItemProps: { label: "用户名" },
props: { placeholder: "请输入用户名", clearable: true },
rules: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
},
{
key: "role",
type: AutoFormItemType.Select,
formItemProps: { label: "角色" },
options: [
{ label: "管理员", value: "admin" },
{ label: "普通用户", value: "user" },
],
},
{
key: "customField",
slotName: "customSlot",
formItemProps: { label: "自定义插槽" },
},
]);
const handleLoaded = (formData: any) => {
console.log("表单加载完成,初始数据:", formData);
};
const submit = async () => {
// 获取 element-plus 的 el-form 实例并校验
await formRef.value?.formRef?.validate();
// 获取组装好的表单数据(自动剔除 isHide 为 true 的字段)
const data = formRef.value?.getFormData();
console.log("提交数据:", data);
};
</script>API 文档
组件属性 (Props)
除了支持 Element-Plus el-form 的所有原生属性外,还支持:
| 属性名 | 说明 | 类型 | 默认值 |
| ------------ | ------------------------------------------ | ---------------- | ------ |
| configList | 表单项配置列表(核心),详情见下文接口定义 | AutoFormItem[] | [] |
组件事件 (Emits)
| 事件名 | 说明 | 回调参数 |
| --------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------- |
| loaded | 表单初始化完成(默认值已挂载)时触发 | (formData: Record<string, any>) => void |
| {customEvent} | 通过 eventsIn 注入的事件抛出 | (eventObj: any, formData: any, itemConfig: AutoFormItem, configList: AutoFormItem[]) => void |
暴露方法 (Exposes)
通过组件的 ref 可调用以下方法/属性:
| 方法名/属性名 | 说明 | 类型 |
| --------------- | -------------------------------------------------------------------- | --------------------------- |
| getFormData() | 获取当前表单数据(自动剔除 isHide 为 true 的字段数据) | () => Record<string, any> |
| resetForm() | 重置表单到初始状态(重新挂载默认值) | () => void |
| formRef | 获取原生的 Element Plus el-form 实例,可用于调用 validate 等方法 | Ref<FormInstance> |
TypeScript 类型定义 (大模型生成必读规范)
mzm-auto-form 依赖高度抽象的配置项。当通过 AI 或手动生成代码时,请严格参考并遵循以下 AutoFormItem 与 AutoFormItemType 接口定义,保证配置的正确性与类型安全。
AutoFormItem 接口定义
export interface AutoFormItem {
/** 表单项绑定字段名 (唯一标识) */
key?: string;
/** 是否隐藏当前项(隐藏后不仅不渲染,getFormData 也不会返回该字段) */
isHide?:
| boolean
| ((formData: Record<string, any>, formItem: AutoFormItem) => boolean);
/** 是否禁用当前项控件 */
isDisabled?:
| boolean
| ((formData: Record<string, any>, formItem: AutoFormItem) => boolean);
/** 控件类型枚举,参考 AutoFormItemType */
type?: AutoFormItemType;
/** 控件默认值,支持直接赋值或函数返回(支持 Promise) */
defaultValue?: any | (() => any);
/** el-form-item 包装层的配置属性 (如 label, label-width 等) */
formItemProps?: Record<string, any>;
/** 表单项验证规则,兼容 Element Plus 规则,支持动态返回 */
rules?:
| Record<string, any>
| ((
formData: Record<string, any>,
formItem: AutoFormItem,
) => Record<string, any>);
/** 内部真实控件 (如 el-input) 的属性配置 */
props?: Record<string, any>;
/** select/radio/checkbox 等控件的选项列表,支持动态异步获取 */
options?:
| { label: string; value: any }[]
| ((
formData: Record<string, any>,
formItem: AutoFormItem,
configList: AutoFormItem[],
) =>
| { label: string; value: any }[]
| Promise<{ label: string; value: any }[]>);
/** 绑定到控件上的事件对象 (原生) */
events?: Record<string, Function>;
/** 事件注入:将控件的事件转发抛出给外层组件的 @[emitName] 事件 */
eventsIn?: { innerName: string; emitName: string }[];
/** 输入框后缀单位文本(仅对 Input 等部分非文本域控件生效) */
valueUnit?: any;
/** 表单项底部描述文本 */
describe?: string;
/** 表单控件内部插槽配置,映射外层插槽到控件内 */
internalSlots?: { innerName: string; slotName: string }[];
/** 初始化数据格式化钩子 */
defaultValueFormatter?: (
defaultValue: any,
itemConfig: AutoFormItem,
) => any;
/** 提交前数据格式化钩子 */
valueFormatter?: (
value: any,
formData: Record<string, any>,
itemConfig: AutoFormItem,
) => any;
/** 自定义整个表单项控件内容的插槽名(优先级高于 type,会替代内置控件) */
slotName?: string;
/** 开发者自定义存储的额外配置数据,组件不消费此字段 */
otherData?: any;
}AutoFormItemType 控件类型枚举
支持丰富的内置控件,使用时推荐引入 AutoFormItemType 进行类型安全的赋值。
export enum AutoFormItemType {
Input = "el-input", // 输入框
InputNumber = "el-input-number", // 数字步进器
InputTag = "el-input-tag", // 标签输入框
ColorPickerPanel = "el-color-picker-panel", // 颜色选择器
Slider = "el-slider", // 滑块
Select = "el-select", // 下拉选择器
SelectTree = "el-tree-select", // 树形下拉选择器
Radio = "el-radio-group", // 单选框组
RadioButton = "el-radio-group_button", // 按钮样式单选框组
Checkbox = "el-checkbox", // 复选框组
DatePicker = "el-date-picker", // 日期选择器
TimePicker = "el-time-picker", // 时间选择器
Switch = "el-switch", // 开关
Cascader = "el-cascader", // 级联选择器
Upload = "mzm-upload", // 文件上传 (内置定制版)
}进阶用法示例
1. 动态表单联动 (显隐与禁用)
可以通过传入函数实现复杂的动态联动,函数参数会自动注入当前表单的完整数据 formData。
{
key: 'reason',
type: AutoFormItemType.Input,
formItemProps: { label: '退回原因' },
// 当 status 为 reject 时才显示
isHide: (formData) => formData.status !== 'reject',
// 动态验证规则
rules: (formData) => {
return formData.status === 'reject'
? [{ required: true, message: '请填写退回原因' }]
: [];
}
}2. 异步拉取选项列表 (Options)
options 支持返回一个 Promise,组件会自动在内部等待并渲染,适用于需要调用后端接口获取字典的场景。
{
key: 'userId',
type: AutoFormItemType.Select,
formItemProps: { label: '选择用户' },
options: async (formData, item) => {
// 模拟后端接口请求
const res = await fetchUserList(formData.departmentId);
return res.data.map(user => ({ label: user.name, value: user.id }));
}
}3. 级联面板 (Cascader) 的使用
级联面板组件在配置 options 时,需要传入符合 CascaderOption 规范的多层级数组。mzm-auto-form 内部已经自动处理了其选项挂载及 label 的渲染插槽逻辑。
{
key: 'region',
type: AutoFormItemType.Cascader,
formItemProps: { label: '所属区域' },
props: {
// Cascader 的原生配置项
props: {
expandTrigger: 'hover',
value: 'code',
label: 'name'
},
placeholder: '请选择所在区域',
clearable: true
},
// 可以是同步的树形数据,也可以是异步请求获取
options: [
{
code: 'zhejiang',
name: '浙江',
children: [
{ code: 'hangzhou', name: '杭州' },
{ code: 'ningbo', name: '宁波' }
]
},
{
code: 'jiangsu',
name: '江苏',
children: [
{ code: 'nanjing', name: '南京' }
]
}
]
}4. 文件上传 (Upload) 的使用
mzm-auto-form 内置了深度定制的文件上传组件 (mzm-upload),支持图片预览、列表管理、单文件/多文件控制,同时允许动态获取 Token 和上传参数。
它的返回值 modelValue 默认支持两种类型:
- 单文件 (默认
limit: 1):返回URL字符串 - 多文件 (
limit > 1):返回逗号分隔的URL字符串 或 字符串数组。
关键专属属性 (props):
action(string): 必填,上传的服务器地址 (同 Element Plus)。uploadType('file' | 'image'): 上传样式类型,默认file,设置为image会展示照片墙模式。limit(number): 最大允许上传个数,默认 1。resolveResponse(Function): 核心钩子,用于从接口返回的数据中提取文件 URL 赋值给表单。headers/data/accept: 均支持直接传对象/字符串,或传入 动态函数(formData, formItem) => value。baseUrl(string): 拼接在返回的 URL 前的域名前缀(多用于相对路径处理)。
{
key: 'avatar',
type: AutoFormItemType.Upload,
formItemProps: { label: '用户头像' },
props: {
action: '/api/upload', // 接口地址
uploadType: 'image', // 使用图片墙模式
limit: 1, // 限制1张
tip: '只能上传 jpg/png 文件,且不超过 2MB',
// 动态获取 Token 等请求头
headers: (formData, item) => ({
Authorization: `Bearer ${localStorage.getItem('token')}`
}),
// 动态附带额外的表单数据
data: (formData) => ({
userId: formData.id,
fileType: 'avatar'
}),
// 核心:提取服务端返回的实际 URL 给到 formData.avatar
// 假设服务端返回: { code: 200, data: { fileUrl: 'https://xxx.png' } }
resolveResponse: (response) => {
return response.data?.fileUrl || '';
}
}
}5. 事件绑定与事件注入 (events vs eventsIn)
组件支持两种方式来处理表单控件内部抛出的原生事件(如 change、blur、focus 等),它们在适用场景和代码结构上有所不同:
(1) events:直接绑定(内联回调)
通过 events 对象,你可以直接在配置项中为控件绑定回调函数。
适用场景:适合处理简单的内部逻辑或调试,不需要将事件与外部 Vue 组件的方法解耦。
参数说明:
在 events 中定义的回调函数,接收四个参数:(formData, itemConfig, configList, args)
formData: 当前表单的全量响应式数据对象itemConfig: 当前表单项的配置对象configList: 完整的表单配置列表args: 底层组件原生事件抛出的参数数组(例如change事件抛出的值会作为args[0])
{
key: 'username',
type: AutoFormItemType.Input,
formItemProps: { label: '用户名' },
events: {
// 监听 el-input 的 blur 事件
blur: (formData, itemConfig, configList, args) => {
console.log('用户名输入框失焦', args[0]); // args[0] 通常是原生 event 对象
},
// 监听 el-input 的 change 事件
change: (formData, itemConfig, configList, args) => {
console.log('值发生改变:', args[0]); // args[0] 是输入的新值
// 直接在此处修改 formData 中的其他值
formData.otherField = '联动值';
}
}
}(2) eventsIn:事件注入(向外抛出)
如果在事件触发时需要调用外部组件的复杂方法(例如触发外层的响应式修改、请求其他接口等),直接在 JSON 配置里写函数会导致代码耦合严重或难以获取 Vue 上下文(如访问不到外部的 ref 变量)。
此时可以使用 eventsIn,将控件的内部事件转发并作为自定义事件抛出给 <mzm-auto-form> 的外层监听。
innerName: 控件原生触发的事件名(如change)。emitName: 转发给<mzm-auto-form>抛出的自定义事件名。注意: 如果
events和eventsIn存在监听同一个内部事件发生冲突,默认以eventsIn优先级更高。
适用场景:适合将业务逻辑集中在 Vue 模板 <script setup> 内统一管理,保持表单配置 JSON 的纯粹性。
参数说明:
抛出到外层的自定义事件回调函数,接收四个参数:(eventArgs, formData, itemConfig, configList)
eventArgs: 底层组件原生事件抛出的参数数组(即包含原生抛出的所有参数,如[val, event])formData: 当前表单的全量数据itemConfig: 当前表单项的配置configList: 完整的表单配置列表
示例:
<template>
<mzm-auto-form
:config-list="formConfig"
@on-city-change="handleCityChange"
/>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { AutoFormItemType, type AutoFormItem } from "mzm-auto-form";
const formConfig = ref<AutoFormItem[]>([
{
key: "city",
type: AutoFormItemType.Select,
formItemProps: { label: "城市" },
options: [
{ label: "北京", value: "beijing" },
{ label: "上海", value: "shanghai" },
],
eventsIn: [
{
innerName: "change", // 监听底层 el-select 的 change 事件
emitName: "on-city-change", // 转发为 on-city-change 事件向外 emit
},
],
},
]);
// 在外部组件中统一处理复杂的业务逻辑
// 接收参数为固定格式:(eventArgs: any[], formData: any, itemConfig: AutoFormItem, configList: AutoFormItem[])
const handleCityChange = (
eventArgs: any[],
formData: any,
itemConfig: AutoFormItem,
configList: AutoFormItem[],
) => {
const selectedValue = eventArgs[0]; // 获取 el-select 抛出的第一个参数(选中的值)
console.log("当前选中的城市值:", selectedValue);
console.log("当前表单全量数据:", formData);
// 可以在这里无缝访问外部的 Vue 响应式变量或调用接口
// fetchCityArea(selectedValue).then(...)
};
</script>