Appearance
字段配置 (fields)
config.fields 中每一项为表单项配置,通用属性如下。
通用属性
| 属性 | 说明 | 类型 |
|---|---|---|
| label | 标签文案,支持 (formData) => string 动态文案 | String | Function |
| key | 对应 model 的字段名,必填(除 component='title'、'text');title/text 仅展示,可不填 key,提交时不会传给后端;computed-text 是可提交的计算展示字段,需要填写 key | String |
| component | 控件类型,见 支持的 component | String |
| placeholder | 占位符;支持 string 或 (formData) => string 动态文案 | String | Function |
| span | 栅格占位(0–24),不填时:title 组件默认 24(整行),其他组件取 config.span,再默认 24 | Number |
| width | 控件宽度,如 '200px'、'50%';用于控制当前字段控件宽度,支持大多数可输入/选择类组件 | String |
| visible | 是否显示该字段;支持 boolean 或 (formData, formType) => boolean,隐藏时字段值仍在 formData 中;formType 为 'add' | 'edit' | 'copy' | 'save' | Boolean | Function |
| disabled | 是否禁用;支持 boolean 或 (formData, formType) => boolean | Boolean | Function |
| readonly | 是否只读;支持 boolean 或 (formData, formType) => boolean;配置了 computed 时自动只读 | Boolean | Function |
| clearable | 是否显示清空按钮,默认 true(部分组件如 switch 不生效) | Boolean |
| labelWidth | 覆盖该字段的 label 宽度,不影响其他字段 | String |
| formItemProps | 透传给 el-form-item 的属性(如 required、showMessage、inlineMessage、size 等) | Object |
| props | 透传给底层 Element Plus 组件的属性,支持对应组件的所有原生 props / attrs;具体可参考 Element Plus 组件文档 | Object |
| computed | 计算字段:(formData) => value,每次表单变化时自动重算并回写到 formData[key];用于输入类控件时控件自动只读,值会参与提交;若只想纯文本展示且提交,请使用 component: 'computed-text' | Function |
| options | 选项列表(select/radio/checkbox);支持静态数组、(formData, context) => Array 或返回 Promise;选项项支持 hidden/disabled(boolean 或 (formData, option) => boolean) | Array | Function |
| optionsDeps | 仅 options 为函数时有效:声明需要监听的 formData 字段名数组(如 ['type', 'status']),当这些字段变化时重新调用 options 函数刷新选项。options(formData, context) 的 context.changedKey / context.changedValue 可获取本次触发来源。未配置则 options 函数仅在挂载时调用一次,不会因表单其他字段变化而重复触发 | Array |
| watchDeps | 声明需监听的 formData 字段名数组;配合 onWatchDeps 在依赖变化时执行回调;任意字段类型均可配置(含 slot 自定义控件);见 watchDeps 依赖监听 | Array |
| onWatchDeps | 依赖变化时的回调 (formData, context) => void | any;可选 return:有返回值且不为 undefined 时写回本字段 key;仅做提示等副作用时可不写 return | Function |
| text | 当 component: 'text' 时的展示内容;支持 string 或 (formData) => string;不填时显示 model[key] 的值;不参与提交;需要展示计算结果并提交时请使用 computed-text;见 text 纯文字展示 | String | Function |
| titleStyle | 当 component='title' 时的标题样式对象;标题文案直接用 label 字段 | Object |
| startKey | 仅 date-range/date-time-range:提交给后端的开始时间字段名,与 endKey 成对使用则提交时自动拆成两个字段 | String |
| endKey | 仅 date-range/date-time-range:提交给后端的结束时间字段名,与 startKey 成对使用 | String |
| extra | 字段控件下方的说明文字;设为 'slot' 时使用插槽 form-extra-[key] 自定义内容 | String |
| tip | 字段 label 旁的问号图标,hover 显示 tooltip 说明 | String |
| prefix | el-input 前缀图标,传入图标组件(如 Search) | Component |
| suffix | el-input 后缀图标,传入图标组件(如 Calendar) | Component |
| prepend | 控件前的辅助内容;支持固定文字或 (formData, field) => string 动态文案;设为 'slot' 时使用插槽 form-prepend-[key] | String | Function |
| append | 控件后的辅助内容;支持固定文字或 (formData, field) => string 动态文案;设为 'slot' 时使用插槽 form-append-[key] | String | Function |
| slot | 完全自定义控件渲染;true 时以 key 作为插槽名,string 时以配置值作为插槽名;插槽名自动补 form- 前缀(已带 form-/search- 则不重复);作用域参数 { modelValue, field, formData };见 slot 自定义控件 | Boolean | String |
| nestedKeys | 配合 slot 使用自定义组件,声明需要嵌套/展平的字段列表;提交时自动展平,回显时自动嵌套 | Array |
| itemFields | 仅 component='array':动态列表每项的子字段配置数组,结构同 fields;兼容别名 columns | Array |
| itemSpan | 仅 array:每项内子字段的栅格占位(0–24),默认 8 | Number |
| minItems | 仅 array:最少保留行数,行数 ≤ 该值时隐藏删除按钮 | Number |
| maxItems | 仅 array:最多允许行数,行数 ≥ 该值时隐藏添加按钮 | Number |
上传字段(component='upload')使用表单级 config.uploadConfig 配置接口、数量、格式等,见 上传配置。单字段可在 field 上配置 uploadConfig 覆盖全局。
支持的 component
| 值 | 说明 | 备注 |
|---|---|---|
| input | 单行输入框 | 可用 field.type 指定 password 等;或直接使用 textarea 类型 |
| textarea | 多行文本输入框 | 支持 rows、autosize、maxlength、showWordLimit 属性 |
| select | 下拉选择 | 需 options |
| select-v2 | 虚拟化下拉选择(el-select-v2),适合万级以上大数据量 | 需 options,选项通过 :options prop 传入 |
| radio | 单选 | 需 options |
| checkbox | 多选 | 需 options |
| title | 分组标题 | 不占表单项,仅展示标题;用 label 字段设置标题文案,可不填 key,不参与提交;span 默认 24(独占整行) |
| text | 纯文字 | 无输入控件,用于展示固定文案或回显字段值;显示内容用 text 字段(支持 string 或 (formData) => string),也可填 key 直接显示 model[key];可不填 key,不参与提交;见 text 纯文字展示 |
| computed-text | 计算文本 | 无输入控件,用于展示 computed 计算结果;需要填写 key,计算结果会写入 formData 并参与提交 |
| date-picker | 日期选择 | Element Plus el-date-picker,可用 props 传 type、value-format 等 |
| date-range | 日期范围 | 同 el-date-picker type="daterange",值为 [start, end],model 默认 [];可配 startKey/endKey 提交为两个字段 |
| date-time-range | 日期时间范围 | 同 el-date-picker type="datetimerange",值为 [start, end],model 默认 [];可配 startKey/endKey 提交为两个字段 |
| time-picker | 时间选择 | |
| time-select | 时间选择(固定步长) | |
| cascader | 级联选择 | 需 options 或 field.props.options |
| input-number | 数字输入 | 可用 props 传 min、max、precision 等 |
| switch | 开关 | |
| slider | 滑块 | |
| rate | 评分 | |
| color-picker | 颜色选择 | |
| transfer | 穿梭框 | 需 props.data 或 options |
| tree-select | 树选择 | 需 props.data 或 options |
| input-tag | 标签输入框,值为字符串数组 | 见 input-tag 配置 |
| upload | 上传 | 需在 config 上配置 uploadConfig(接口、数量、格式、大小);上传后支持拖拽排序 |
| array | 动态列表(可增删项),每项为子表单项集合 | 见 array 配置 |
下拉/单选/多选的选项格式:{ label: string, value: any, hidden?: boolean | (formData, option) => boolean, disabled?: boolean | (formData, option) => boolean }。
date-range / date-time-range 提交为两个字段:若后端需要 startTime、endTime 两个字段,可配置 startKey、endKey。表单内部仍用 key 存 [start, end],校验规则建议写在表单配置的 rules 中并使用该 key;提交时自动拆成 payload[startKey]、payload[endKey],回显时若接口返回 startKey/endKey 会自动合成 key 用于展示。
javascript
{ label: '日期范围', key: 'dateRange', component: 'date-range', startKey: 'startTime', endKey: 'endTime' }uploadConfig(上传配置)
上传配置独立成页,完整配置项、字段级覆盖与示例见 上传配置。
visible / disabled / readonly — 动态显隐与禁用
三个属性均支持函数形式 (formData, formType) => boolean,formType 为 'add' | 'edit' | 'copy' | 'save'(ProForm 独立使用时默认为 'add'),可实现字段间联动与新增 / 编辑差异化控制。若需在依赖变化时执行副作用(提示、清空、按状态回填默认值等),见 watchDeps 依赖监听;若需随任意表单变化自动重算本字段值,见 computed 或 computed-text。
js
fields: [
{ label: '类型', key: 'type', component: 'select',
options: [{ label: '类型 A', value: 'A' }, { label: '类型 B', value: 'B' }] },
{
label: '子类型', key: 'subType', component: 'select',
// 类型未选时禁用
disabled: (d) => !d.type,
// 选项随类型动态变化
options: (d) => {
if (d.type === 'A') return [{ label: 'A1', value: 'A1' }, { label: 'A2', value: 'A2' }]
if (d.type === 'B') return [{ label: 'B1', value: 'B1' }, { label: 'B2', value: 'B2' }]
return []
}
},
{ label: '开启时效', key: 'enabled', component: 'switch' },
{
label: '过期时间', key: 'expireTime', component: 'date-picker',
// 开关打开时才显示
visible: (d) => d.enabled === true
},
{
label: '备注', key: 'remark', component: 'input',
// 子类型未选时禁用
disabled: (d) => !d.subType
}
]js
fields: [
{ label: '是否开启', key: 'enabled', component: 'switch' },
{
label: '过期时间',
key: 'expireTime',
component: 'date-picker',
visible: (formData) => formData.enabled === true // 开启时才显示
},
{
label: '备注',
key: 'remark',
component: 'input',
disabled: (formData) => formData.status === 2 // 状态为 2 时禁用
},
{
label: '编号',
key: 'code',
component: 'input',
readonly: (formData, formType) => formType === 'edit' // 编辑时只读,新增时可编辑
},
{
label: '管理员备注',
key: 'adminRemark',
component: 'textarea',
readonly: (formData) => formData.role !== 'admin' // 非管理员角色时只读
}
]
visible: false只是隐藏控件,字段值仍存在 formData 中并会提交。如需提交时排除,在paramsFormat中手动删除即可。
computed 会在每次表单数据变化时自动执行,并把结果写入 formData[key]。如果希望像普通文本一样展示、但仍作为字段提交,请使用 component: 'computed-text'。
与 component: 'text' 的区别:text 仅展示、不参与提交;computed-text 是计算展示字段,会提交。
js
fields: [
{ label: '数量', key: 'quantity', component: 'input-number' },
{ label: '单价(元)', key: 'unitPrice', component: 'input-number' },
{
label: '总价(元)', key: 'totalPrice', component: 'computed-text',
computed: (d) => ((d.quantity || 0) * (d.unitPrice || 0)).toFixed(2)
},
{ label: '姓', key: 'lastName', component: 'input', span: 8 },
{ label: '名', key: 'firstName', component: 'input', span: 8 },
{
label: '全名', key: 'fullName', component: 'computed-text', span: 8,
computed: (d) => [d.lastName, d.firstName].filter(Boolean).join(' ')
}
]options — 动态选项
options 支持三种形式:
js
// 1. 静态数组
options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }]
// 2. 同步函数(根据其他字段联动)
options: (formData, context) => formData.type === 'A'
? [{ label: 'A1', value: 'a1' }, { label: 'A2', value: 'a2' }]
: [{ label: 'B1', value: 'b1' }]
// 3. 异步函数(组件挂载时自动请求)
options: async (formData, context) => {
const res = await getDeptList(formData.companyId)
return res.data.map(item => ({ label: item.name, value: item.id }))
}当 options 为函数时,第二个参数 context 可用字段如下:
| 字段 | 说明 |
|---|---|
| changedKey | 本次由哪个依赖字段触发;初始化加载时为 undefined |
| changedValue | 本次触发字段的当前值 |
| changedKeys | 本次变化的依赖字段列表 |
| optionsDeps | 当前配置的 optionsDeps |
| field | 当前字段配置 |
| triggerType | 触发类型:'init' / 'deps-change' / 'manual' |
| formData | 当前完整表单数据 |
例如:
js
{
label: '子类型',
key: 'subType',
component: 'select',
optionsDeps: ['type', 'status'],
options: async (formData, { changedKey, changedValue, triggerType }) => {
if (triggerType === 'deps-change' && changedKey === 'type') {
console.log('类型变更为:', changedValue)
}
return fetchSubTypeOptions(formData)
}
}若需监听依赖变化刷新选项列表,使用
optionsDeps;若需监听依赖变化执行任意副作用或重算本字段(含slot自定义控件),使用 watchDeps。
watchDeps — 字段依赖监听
optionsDeps 仅作用于 options 为函数 的选项类字段。若需要在 任意字段(含 slot 自定义控件)上监听其他字段变化并执行副作用或重算本字段值,使用 watchDeps + onWatchDeps。
| 属性 | 说明 |
|---|---|
watchDeps | 需要监听的 formData 字段名数组,如 ['status', 'type'] |
onWatchDeps | (formData, context) => void | any,依赖变化时调用;可选 return 写回本字段 key(不为 undefined 时生效) |
context 字段与 options(formData, context) 对齐:
| 字段 | 说明 |
|---|---|
changedKey | 本次由哪个依赖字段触发;初始化时为 undefined |
changedValue | 本次触发字段的当前值 |
changedKeys | 本次变化的依赖字段列表 |
watchDeps | 当前配置的 watchDeps |
field | 当前字段配置 |
triggerType | 'init' / 'deps-change' |
formData | 当前完整表单数据 |
与 computed 的区别:computed 在任意表单变化时重算;watchDeps 仅在指定依赖变化时触发,适合做提示、清空、按状态回填默认值等副作用。
js
{
label: '备注',
key: 'remark',
slot: true,
span: 24,
watchDeps: ['status'],
onWatchDeps: (formData, { changedKey, changedValue, triggerType }) => {
if (triggerType !== 'init' && changedKey === 'status') {
console.log('状态变更为', changedValue)
}
// 禁用时若备注为空,自动填入提示文案(返回值会写入 remark)
if (formData.status === 0 && !formData.remark) {
return '请填写禁用原因'
}
},
extra: (formData) => (formData.status === 0 ? '禁用时请填写原因' : '最多 200 字')
}
return不是必须的。只做提示、打日志、改其他字段等副作用时,不写return即可。需要更新本字段时用return;改其他字段可直接写formData.xxx。
仅当
watchDeps中声明的字段值发生变化时才会触发(其他字段变更导致formData整体替换不会误触发)。
props — 透传底层控件属性
props 可以使用底层 Element Plus 组件的所有原生属性:
js
fields: [
// textarea:推荐直接使用 component: 'textarea'
{ label: '描述', key: 'desc', component: 'textarea', rows: 4, maxlength: 200, showWordLimit: true },
// 也可通过 input + props.type 实现(兼容旧写法)
// { label: '描述', key: 'desc', component: 'input', props: { type: 'textarea', rows: 4 } },
// 数字范围和精度
{ label: '折扣', key: 'discount', component: 'input-number',
props: { min: 0, max: 100, precision: 1, step: 5 } },
// 日期格式化
{ label: '日期', key: 'date', component: 'date-picker',
props: { valueFormat: 'YYYY-MM-DD', format: 'YYYY年MM月DD日' } },
// 多选 + 可搜索的 select
{ label: '标签', key: 'tags', component: 'select', options: tagOptions,
props: { multiple: true, filterable: true, collapseTags: true } }
]slot — 自定义控件
当内置 component 无法满足需求时,可通过 slot 完全自定义字段控件。配置 slot 后不再渲染默认控件,由你在 ProForm / ProFormPopup 模板中提供对应插槽内容。
插槽名规则
表单字段插槽名由 normalizeSlotName 规范化:默认自动补 form- 前缀;若配置值已以 form- 或 search- 开头则保持原样。
| 字段配置 | 模板插槽名 | 说明 |
|---|---|---|
key: 'remark', slot: true | #form-remark | true 时使用 key 作为插槽名 |
key: 'remark', slot: 'remark' | #form-remark | 字符串配置,自动补前缀 |
key: 'remark', slot: 'form-remark' | #form-remark | 已带 form- 前缀,不重复添加 |
key: 'status', slot: 'status' | #form-status | 插槽名与 key 可不同 |
作用域参数
| 参数 | 说明 |
|---|---|
modelValue | 当前字段值,与 field.key 对应 |
field | 当前字段完整配置(含 options、props 等) |
formData | 整表数据对象,可直接 v-model 修改联动字段 |
数据绑定方式
- 推荐:在插槽内使用
modelValue+@update:modelValue,或v-model绑定自定义子组件 - 也可:直接修改
formData[field.key]或formData.xxx(适合简单场景,如 textarea)
配置了 slot 的字段仍会参与校验:rules 写在表单 rules 或字段 rules 中,使用字段 key 作为 prop。
字段级辅助插槽(与 slot 配合使用)
| 字段配置 | 模板插槽名 | 作用域参数 |
|---|---|---|
extra: 'slot' | #form-extra-[key] | { field, formData, modelValue } |
prepend: 'slot' | #form-prepend-[key] | 同上 |
append: 'slot' | #form-append-[key] | 同上 |
完整插槽总览见 插槽总览。
vue
<ProForm :config="formConfig" @submit="onSubmit">
<!-- slot: true + key: remark → #form-remark -->
<template #form-remark="{ formData }">
<el-input
v-model="formData.remark"
type="textarea"
:rows="3"
placeholder="自定义备注控件"
maxlength="200"
show-word-limit
/>
</template>
<!-- slot: 'status' → #form-status -->
<template #form-status="{ formData, field }">
<el-radio-group v-model="formData.status">
<el-radio v-for="opt in field.options" :key="opt.value" :value="opt.value">
{{ opt.label }}
</el-radio>
</el-radio-group>
</template>
</ProForm>js
fields: [
{
label: '状态',
key: 'status',
slot: 'status',
options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }]
},
{
label: '备注',
key: 'remark',
slot: true, // 等价于 slot: 'remark',插槽名均为 #form-remark
span: 24
}
]若自定义组件内部操作嵌套对象并需在提交时展平,可配合 nestedKeys 使用。监听其他字段变化做副作用时,可配合 watchDeps。
extra / tip / prepend / append — 辅助内容
prepend / append 支持三种用法:
- 固定文字:
prepend: '+86' - 动态文案:
append: (formData, field) => formData.currency === 'USD' ? '美元' : '人民币' - 自定义插槽:
prepend: 'slot'/append: 'slot',插槽作用域参数为{ field, formData, modelValue }
vue
<ProForm :config="formConfig">
<template #form-extra-remark="{ formData }">
<span>当前字数:{{ formData.remark?.length || 0 }}</span>
</template>
<template #form-prepend-amount="{ formData }">
{{ formData.currency === 'USD' ? '$' : '¥' }}
</template>
<template #form-append-amount="{ formData }">
{{ formData.currency === 'USD' ? '美元' : '人民币' }}
</template>
</ProForm>js
import { Search } from '@element-plus/icons-vue'
fields: [
{
label: '手机号', key: 'phone', component: 'input',
tip: '请输入 11 位手机号', // label 旁问号 tooltip
extra: '格式:138xxxxxxxx', // 控件下方说明文字
prefix: Search, // input 前缀图标
prepend: '+86' // 控件前固定文字
},
{
label: '币种', key: 'currency', component: 'select',
options: [{ label: '人民币', value: 'CNY' }, { label: '美元', value: 'USD' }]
},
{
label: '汇率', key: 'rate', component: 'input-number',
prepend: (formData) => formData.currency === 'USD' ? '$' : '¥',
append: (formData) => formData.currency === 'USD' ? '美元汇率' : '人民币汇率'
},
{
label: '金额', key: 'amount', component: 'input-number',
prepend: 'slot', // 使用插槽 #form-prepend-amount,插槽可获取 formData
append: 'slot' // 使用插槽 #form-append-amount,插槽可获取 formData
},
{
label: '备注', key: 'remark', component: 'textarea',
extra: 'slot' // 使用插槽 #form-extra-remark
}
]startKey / endKey — 日期范围拆字段
后端需要 startTime、endTime 两个字段时,配置 startKey/endKey,表单内部用 key 存 [start, end],提交时自动拆开;回显时若接口返回 startKey/endKey 会自动合成数组供控件展示:
js
{
label: '日期范围',
key: 'dateRange',
component: 'date-range',
startKey: 'startTime',
endKey: 'endTime',
rules: [{ required: true, message: '请选择日期范围' }]
}
// 提交时:{ startTime: '2024-01-01', endTime: '2024-12-31' }
// 回显时:接口返回 startTime/endTime 自动合成 dateRange: ['2024-01-01', '2024-12-31']nestedKeys — 自定义组件数据展平与嵌套
当使用 slot 自定义组件时,组件内部操作的是一个嵌套对象(如 { user: { name, phone, age } }),但后端接口需要展平的字段(如 { name, phone, age })。配置 nestedKeys 可以自动处理这个转换。
工作原理
| 阶段 | 行为 |
|---|---|
| 提交时 | 自动展平:{ user: { name, phone } } → { name, phone },删除 user 键 |
| 回显时 | 自动嵌套:接口返回 { name, phone } → 组装成 { user: { name, phone } } 供自定义组件使用 |
配置方式
js
fields: [
{
label: '用户信息',
key: 'user',
slot: 'form-userInfo',
nestedKeys: ['name', 'phone', 'age']
}
]key: 'user'— formData 中存储嵌套对象的字段名nestedKeys: ['name', 'phone', 'age']— 声明哪些子字段属于这个嵌套对象slot— 用自定义组件渲染
完整示例
js
const formConfig = reactive({
mode: 'dialog',
model: { user: {}, remark: '' },
fields: [
{
label: '用户详情',
key: 'user',
slot: 'form-userInfo',
nestedKeys: ['name', 'phone', 'age']
},
{ label: '备注', key: 'remark', component: 'input' }
],
fetchInitialData: async (params) => {
// 接口返回展平数据:{ name: 'Alice', phone: '123', age: 30, remark: 'xxx' }
// 组件自动嵌套为:{ user: { name, phone, age }, remark: 'xxx' }
return await getDetail(params.id)
},
add: {
title: '新增',
api: async (data) => {
// data 已自动展平:{ name: 'Alice', phone: '123', age: 30, remark: 'xxx' }
return await createRecord(data)
}
},
edit: {
title: '编辑',
api: async (data) => {
// data 已自动展平:{ name: 'Alice', phone: '123', age: 30, id: 1, remark: 'xxx' }
return await updateRecord(data)
}
}
})模板中提供自定义组件插槽:
vue
<ProFormPopup v-model:visible="visible" :config="formConfig">
<template #form-userInfo="{ modelValue, formData }">
<UserInfoForm v-model="modelValue" />
</template>
</ProFormPopup>自定义组件 UserInfoForm.vue:
vue
<template>
<div>
<el-form-item label="姓名">
<el-input v-model="userData.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="电话">
<el-input v-model="userData.phone" placeholder="请输入电话" />
</el-form-item>
<el-form-item label="年龄">
<el-input-number v-model="userData.age" :min="0" :max="120" />
</el-form-item>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
modelValue: { type: Object, default: () => ({}) }
})
const emit = defineEmits(['update:modelValue'])
const userData = computed({
get: () => props.modelValue ?? {},
set: (val) => emit('update:modelValue', val)
})
</script>数据流转过程
接口返回(展平) → nestedKeys 自动嵌套 → 自定义组件使用
{ name, phone } → { user: {name, phone} } → UserInfoForm
自定义组件修改 → nestedKeys 自动展平 → 提交给接口
{ user: {name, phone} } → { name, phone } → api(data)注意事项
- ProForm 和 ProFormPopup 均支持 nestedKeys,提交时自动展平、
fetchInitialData回显时自动嵌套 model中需要声明嵌套字段的初始值(如{ user: {} }),否则自定义组件首次渲染可能拿到 undefined- nestedKeys 的展平在
paramsFormat之前执行,paramsFormat拿到的已经是展平后的数据
text — 纯文字展示
component: 'text' 用于在表单中展示一段只读文字,没有输入控件,不参与提交。显示内容的取值优先级:field.text > model[key]。
| 写法 | 说明 | 示例 |
|---|---|---|
text 固定文案 | 可不填 key,直接展示固定文字 | { label: '提示', component: 'text', text: '请仔细核对信息后提交' } |
text 动态文案 | 支持 (formData) => string,随其他字段联动 | { label: '应付金额', component: 'text', text: (d) => ¥${d.amount |
key 回显 | 填 key 不填 text,直接显示 model[key] 的值(如详情回显) | { label: '用户名', key: 'username', component: 'text' } |
js
fields: [
// 1. 固定文案:可不填 key
{ label: '温馨提示', component: 'text', text: '提交后不可修改,请仔细核对' },
// 2. 回显字段值:填 key 不填 text,显示 model.username
{ label: '用户名', key: 'username', component: 'text' },
// 3. 动态文案:随其他字段联动
{ label: '应付金额', component: 'text', text: (formData) => `¥${formData.amount || 0}` }
]需要展示计算结果并且提交时,请使用
component: 'computed-text'+computed,而不是text。
textarea — 多行文本输入框
component: 'textarea' 是专用的多行文本控件,基于 el-input 的 textarea 模式封装,支持以下专属配置属性(直接写在 field 上,无需放入 props):
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| rows | 固定行数 | Number | 2 |
| autosize | 自适应高度;传 true 或 { minRows, maxRows } | Boolean | Object | - |
| maxlength | 最大字符数 | Number | - |
| showWordLimit | 是否显示字数统计(需同时设置 maxlength) | Boolean | false |
disabled、readonly、clearable、placeholder(支持函数)、props等通用属性同样生效。
js
fields: [
{ label: '备注', key: 'remark', component: 'textarea', placeholder: '请输入备注' },
{ label: '描述', key: 'desc', component: 'textarea', rows: 4 },
{ label: '内容', key: 'content', component: 'textarea', autosize: { minRows: 2, maxRows: 6 } },
{ label: '简介', key: 'intro', component: 'textarea', maxlength: 200, showWordLimit: true }
]兼容旧写法:
component: 'input'配合props: { type: 'textarea' }依然有效,但推荐直接使用component: 'textarea',rows/autosize/maxlength/showWordLimit可直接写在 field 上而无需嵌套到props中。
input-tag — 标签输入框
component: 'input-tag' 时,字段值为字符串数组(string[]),用户在输入框内输入内容后按 Enter 或失焦自动添加为标签,按 Backspace 删除最后一个标签,点击标签上的 × 删除指定标签。
专属配置项
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| max | 最多可添加的标签数量 | Number | - |
| unique | 是否自动去重 | Boolean | true |
| addOnBlur | 失焦时是否自动添加当前输入内容 | Boolean | true |
| maxTagLength | 单个标签的最大字符长度 | Number | - |
| tagType | 标签类型:''、'success'、'warning'、'danger'、'info' | String | '' |
| tagSize | 标签尺寸:'large'、'default'、'small' | String | 'default' |
js
fields: [
{
label: '技能标签', key: 'tags', component: 'input-tag',
placeholder: '输入后按 Enter 添加',
tip: '按 Enter 或失焦添加,按 Backspace 删除最后一个'
},
{ label: '最多3个', key: 'limitTags', component: 'input-tag', max: 3 },
{
label: '成功样式', key: 'styleTags', component: 'input-tag',
tagType: 'success', tagSize: 'small'
}
]
// model: { tags: [], limitTags: [], styleTags: [] }
// 提交时:{ tags: ['Vue', 'React'], limitTags: [...], styleTags: [...] }array — 动态列表
component: 'array' 提供可增删的动态子表单列表,每行是一组字段,适合联系人列表、商品规格等场景。字段值为对象数组。
专属配置项
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| itemFields | 每行的子字段配置数组,结构同 fields;兼容别名 columns | Array | [] |
| itemSpan | 每行内子字段的栅格占位(0–24) | Number | 8 |
| gutter | 子字段间距 | Number | 20 |
| defaultItem | 新增一行时的默认数据;支持对象或 (formData) => Object;仅在点击新增时生效,不会自动生成初始行 | Object | Function | 各字段空值 |
| minItems | 最少保留行数;当列表行数 ≤ 该值时隐藏删除按钮 | Number | 0 |
| maxItems | 最多允许行数;当列表行数 ≥ 该值时隐藏添加按钮 | Number | 无限制 |
提示:如需默认显示一行,请在表单
model中预置数组(如contacts: [defaultRow]),defaultItem仅用于「新增」按钮生成新行。
js
fields: [
{
label: '联系人',
key: 'contacts',
component: 'array',
span: 24,
itemSpan: 8, // 每个子字段占 8 格,一行三列
itemFields: [
{
label: '姓名', key: 'name', component: 'input',
rules: [{ required: true, message: '请输入姓名', trigger: 'blur' }]
},
{ label: '手机号', key: 'phone', component: 'input' },
{
label: '角色', key: 'role', component: 'select',
options: [
{ label: '负责人', value: 'owner' },
{ label: '开发', value: 'dev' },
{ label: '测试', value: 'qa' }
]
}
]
}
]
// model: { contacts: [{ name: '', phone: '', role: '' }] }
// 提交时:{ contacts: [{ name: '张三', phone: '138xxxx', role: 'owner' }, ...] }
itemFields中的子字段同样支持visible、disabled、readonly、rules等通用属性,disabled/visible/readonly函数签名同样为(formData, formType) => boolean,其中formData中包含_row(当前行数据)和_rowIndex(当前行索引),可用于行内联动。
js
// 行内联动示例:类型为 B 时才显示备注
itemFields: [
{
label: '类型', key: 'type', component: 'select',
options: [{ label: 'A', value: 'A' }, { label: 'B', value: 'B' }]
},
{
label: '备注', key: 'remark', component: 'input',
visible: (formData) => formData._row?.type === 'B'
}
]minItems / maxItems 示例
js
{
label: '联系人',
key: 'contacts',
component: 'array',
span: 24,
minItems: 1, // 至少保留 1 行,只剩 1 行时不显示删除按钮
maxItems: 5, // 最多 5 行,达到 5 行时不显示添加按钮
itemFields: [
{ label: '姓名', key: 'name', component: 'input' },
{ label: '手机号', key: 'phone', component: 'input' }
]
}
// model: { contacts: [{ name: '', phone: '' }] }