Skip to content

字段配置 (fields) ​

config.fields 中每一项为表单项配置,通用属性如下。

通用属性 ​

属性说明类型
label标签文案,支持 (formData) => string 动态文案String | Function
key对应 model 的字段名,必填(除 component='title'、'text');title/text 仅展示,可不填 key,提交时不会传给后端;computed-text 是可提交的计算展示字段,需要填写 keyString
component控件类型,见 支持的 componentString
placeholder占位符;支持 string 或 (formData) => string 动态文案String | Function
span栅格占位(0–24),不填时:title 组件默认 24(整行),其他组件取 config.span,再默认 24Number
width控件宽度,如 '200px'、'50%';用于控制当前字段控件宽度,支持大多数可输入/选择类组件String
visible是否显示该字段;支持 boolean 或 (formData, formType) => boolean,隐藏时字段值仍在 formData 中;formType 为 'add' | 'edit' | 'copy' | 'save'Boolean | Function
disabled是否禁用;支持 boolean 或 (formData, formType) => booleanBoolean | 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;仅做提示等副作用时可不写 returnFunction
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
prefixel-input 前缀图标,传入图标组件(如 Search)Component
suffixel-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;兼容别名 columnsArray
itemSpan仅 array:每项内子字段的栅格占位(0–24),默认 8Number
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-remarktrue 时使用 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]同上

完整插槽总览见 插槽总览。

备注字段用 `slot: true` 自定义 textarea;状态字段用 `slot: 'status'` 自定义单选组。
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 }
手机号带前缀图标和固定前缀文字;汇率根据币种动态显示前后缀;金额用 slot 自定义前后缀;备注下方显示动态字数统计。
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固定行数Number2
autosize自适应高度;传 true 或 { minRows, maxRows }Boolean | Object-
maxlength最大字符数Number-
showWordLimit是否显示字数统计(需同时设置 maxlength)Booleanfalse

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是否自动去重Booleantrue
addOnBlur失焦时是否自动添加当前输入内容Booleantrue
maxTagLength单个标签的最大字符长度Number-
tagType标签类型:''、'success'、'warning'、'danger'、'info'String''
tagSize标签尺寸:'large'、'default'、'small'String'default'
按 Enter 添加标签;第二行最多添加 3 个;第三行绿色小尺寸样式。
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;兼容别名 columnsArray[]
itemSpan每行内子字段的栅格占位(0–24)Number8
gutter子字段间距Number20
defaultItem新增一行时的默认数据;支持对象或 (formData) => Object;仅在点击新增时生效,不会自动生成初始行Object | Function各字段空值
minItems最少保留行数;当列表行数 ≤ 该值时隐藏删除按钮Number0
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: '' }] }