Appearance
ProForm 表单
ProForm 是配置化表单组件,适用于设置页、个人信息页、整页编辑等场景。
如需弹窗 / 抽屉表单,见 ProFormPopup 弹层表单。与 ProTable 联动的 formConfig 配置见 表单弹层配置。
基本用法
vue
<template>
<ProForm :config="formConfig" @submit="onSubmit" />
</template>
<script setup>
const formConfig = {
title: '用户信息',
labelWidth: '90px',
span: 12,
model: { name: '', status: 1, remark: '' },
fields: [
{ label: '姓名', key: 'name', component: 'input' },
{ label: '状态', key: 'status', component: 'select',
options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }] },
{ label: '备注', key: 'remark', component: 'textarea',
rows: 3, maxlength: 200, showWordLimit: true, span: 24 }
],
rules: {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }]
},
footer: { show: true, showSubmit: true, showReset: true, align: 'left' }
}
function onSubmit(data) { console.log(data) }
</script>回填初始数据
配置 fetchInitialData 后,组件挂载时自动请求并回填表单:
js
const formConfig = {
model: { name: '', status: 1 },
params: { id: userId },
fetchInitialData: async (params) => {
const res = await getUserDetail(params.id)
return res.data
},
api: async (data) => {
await updateUser(data)
},
fields: [
{ label: '姓名', key: 'name', component: 'input' },
{ label: '状态', key: 'status', component: 'select', options: [...] }
]
}Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| config | 表单配置对象,见下方 Config | Object | {} |
| readonly | 外部控制只读,优先于 config.readonly | Boolean | undefined |
Config 配置
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| model | 表单初始数据 | Object | - |
| title | 表单标题 | String | - |
| fields | 表单项配置数组,见 字段配置 | Array | [] |
| tabs | 分 tab 展示,见 tabs 配置 | Array | - |
| labelWidth | label 宽度 | String | '100px' |
| labelPosition | label 对齐:left / right / top | String | 'left' |
| formAttrs | 透传给 el-form 的属性(size、disabled、labelSuffix 等) | Object | - |
| span | 表单项栅格占位(每行 24 格),可在 field 上单独覆盖 | Number | 24 |
| formWidth | 表单内容区宽度,如 '600px'、'80%' | String | - |
| params | 传给 fetchInitialData 的参数 | Object | {} |
| fetchInitialData | 挂载时请求回填:(params) => Promise<Object> | Function | - |
| api | 提交接口:(params) => Promise,不配置时仅触发 submit 事件 | Function | - |
| filterEmptyParams | 提交前是否过滤空值;设为 true 时过滤 ''、null、undefined、空数组 | Boolean | false |
| paramsFormat | 提交前对最终参数做转换:(data) => any | Function | - |
| responseFormat | 请求成功后对响应做转换:(res) => any | Function | - |
| rules | 表单校验规则 | Object | - |
| beforeSubmit | 提交前钩子:({ formData, action }) => boolean | Promise<boolean>,返回 false 取消 | Function | - |
| afterSubmit | 提交成功后回调:({ res, formData, action }) => void | Function | - |
| readonly | 表单级只读:true 时所有字段只读;支持 (formType) => boolean | Boolean | Function | false |
| uploadConfig | 上传配置,见 上传配置 | Object | - |
| footer | 底部区域配置,见 Footer | Object | {} |
字段联动
字段间联动常用方式如下,完整说明见 字段配置:
| 场景 | 配置 | 说明 |
|---|---|---|
| 显隐 / 禁用 / 只读 | visible / disabled / readonly | 支持 (formData) => boolean |
| 自动重算本字段值 | computed / component: 'computed-text' | 任意表单变化时重算并写回 key |
| 动态选项列表 | options 函数 + optionsDeps | 仅选项类字段;依赖变化时重新加载 options |
| 依赖变化副作用 | watchDeps + onWatchDeps | 任意字段(含 slot);提示、清空、按状态回填等 |
| 自定义控件 | slot: true / slot: 'xxx' | 插槽名规范见 slot 自定义控件 |
watchDeps 示例:备注字段监听状态变化,禁用时自动填入默认文案:
js
{
label: '备注',
key: 'remark',
slot: true,
watchDeps: ['status'],
onWatchDeps: (formData, { changedKey, changedValue, triggerType }) => {
if (triggerType !== 'init' && changedKey === 'status') {
console.log('状态变更为', changedValue)
}
if (formData.status === 0 && !formData.remark) {
return '请填写禁用原因'
}
}
}提交流程与钩子职责
表单提交时会先基于当前表单数据生成提交参数:日期范围字段会按 startKey / endKey 拆分,title / text 展示字段不会提交,nestedKeys 字段会在提交时展平。
如果配置了 filterEmptyParams: true,会在 paramsFormat 之前过滤 ''、null、undefined 和空数组。默认不启用,避免清空字段时无法把空值提交给后端。
执行顺序:
text
表单校验 → beforeSubmit → 生成提交参数 → filterEmptyParams → paramsFormat → api → responseFormat → afterSubmit → submit 事件paramsFormat 与 beforeSubmit
beforeSubmit用于提交前拦截、二次确认或业务校验。paramsFormat用于转换最终提交参数,例如字段改名、类型转换、补充固定字段。
不建议在 beforeSubmit 中做参数转换,参数转换统一放到 paramsFormat。
beforeSubmit 返回值行为
beforeSubmit 的返回值决定后续流程:
js
beforeSubmit: ({ formData, action }) => {
// 1. 返回 false(同步)→ 取消本次提交,弹层/表单保持不变
if (某些条件) return false
// 2. 返回 Promise.resolve(false) → 同上,取消提交
return someAsyncCheck().then(result => {
if (!result) return false
})
// 3. 抛出异常(或返回 rejected Promise)→ 取消提交,显示错误提示
throw new Error('业务校验失败')
// 4. 返回 true / undefined / 返回值 → 继续后续提交流程
return true
}| 返回值 | 行为 |
|---|---|
false | 取消提交,表单保持原样 |
Promise<false> | 同上(异步场景) |
抛出异常 / Promise.reject | 取消提交,显示错误提示 |
true / undefined / 其他 | 继续执行后续提交逻辑 |
responseFormat 与 afterSubmit
responseFormat用于转换接口响应,它的返回值会作为afterSubmit和submit事件接收到的响应。afterSubmit用于提交成功后的副作用,例如跳转、刷新外部数据、记录日志等。
接口返回对象中包含全局 codeKey 字段时,会先根据全局 successCode 判断成功 / 失败;失败时会提示错误并中断 responseFormat、afterSubmit 和 submit 事件。
tabs 配置
当表单项较多时,可用 config.tabs 将字段分到多个 tab 中展示:
js
const formConfig = {
labelWidth: '90px',
model: { name: '', phone: '', email: '', isEmployee: false, company: '', position: '', city: '', remark: '' },
tabs: [
{
label: '基本信息', name: 'basic',
fields: [
{ label: '姓名', key: 'name', component: 'input', span: 12,
rules: [{ required: true, message: '请输入姓名' }] },
{ label: '手机号', key: 'phone', component: 'input', span: 12 },
{ label: '邮箱', key: 'email', component: 'input', span: 24 },
{ label: '是否在职', key: 'isEmployee', component: 'switch', span: 24 }
]
},
{
label: '工作信息', name: 'work',
disabled: (formData) => formData.isEmployee !== true,
fields: [
{ label: '公司', key: 'company', component: 'input', span: 12 },
{ label: '职位', key: 'position', component: 'input', span: 12 },
{ label: '城市', key: 'city', component: 'select', span: 12,
options: [{ label: '北京', value: 'beijing' }, { label: '上海', value: 'shanghai' }] },
{ label: '备注', key: 'remark', component: 'textarea', rows: 3, span: 24 }
]
},
{
label: '高级设置', name: 'advanced',
hidden: (formData) => !formData.name,
fields: [
{ label: '说明', key: 'advancedRemark', component: 'textarea', rows: 3, span: 24 }
]
}
],
footer: { show: true, showSubmit: true, showReset: true }
}| 属性 | 说明 | 类型 |
|---|---|---|
| label | tab 显示名称 | String |
| name | tab 唯一标识,不传时默认 tab0、tab1… | String |
| fields | 该 tab 下的表单项配置数组,结构同 字段配置 | Array |
| hidden | 是否隐藏该 tab;支持 boolean 或 (formData, tab) => boolean | Boolean | Function |
| disabled | 是否禁用该 tab;支持 boolean 或 (formData, tab) => boolean | Boolean | Function |
校验规则、computed 联动会基于所有 tab 的 fields 合并后的结果生效。
Footer 配置
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| show | 是否显示底部 | Boolean | true |
| showSubmit | 是否显示提交按钮 | Boolean | true |
| showReset | 是否显示重置按钮 | Boolean | false |
| submitText | 提交按钮文案 | String | '提交' |
| resetText | 重置按钮文案 | String | '重置' |
| align | 按钮对齐:left / center / right | String | 'left' |
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| submit | 校验通过且(若有 api)请求成功后触发 | (response | formData, formData) |
| reset | 点击重置按钮后触发 | - |
submit事件:第一个参数为接口响应(配置了api时)或表单数据(未配置时),第二个始终为提交时的表单原始数据。
Ref 方法
| 方法 | 说明 |
|---|---|
submit() | 手动触发提交(校验 + 请求) |
reset() | 重置表单为初始值 |
getFormData() | 获取当前表单数据(副本) |
setFormData(data) | 设置整表数据 |
patchFormData(patch) | 部分更新表单数据 |
validate() | 触发表单校验,返回 Promise |
clearValidate() | 清除校验状态 |
setActiveTab(name) | 主动切换到指定 tab |
getActiveTab() | 获取当前激活的 tab name |
loading | 当前是否处于加载中(ref) |
Slots
| 插槽名 | 说明 | 作用域参数 |
|---|---|---|
| form-header | 表单内容区顶部 | |
| form-footer | 表单内容区底部 | 同上 |
| footer-before | 按钮区域左侧 | 同上 |
| footer-after | 按钮区域右侧 | 同上 |
| [field.slot] | 字段自定义控件 | |
| extra-[key] | 字段下方扩展内容 | |
| prepend-[key] | 控件前插槽 | 同上 |
| append-[key] | 控件后插槽 | 同上 |
字段级插槽会返回当前完整 formData,可根据其他字段值渲染不同内容;例如 #form-append-amount="{ formData }" 中可读取 formData.currency。prepend / append 不使用插槽时也支持函数写法:(formData, field) => string。
更多事件与方法说明见 事件与实例方法。