Skip to content

完整示例 ​

fetchInitialData、字段联动、插槽的综合示例。

独立页面表单 ​

挂载时自动调用 fetchInitialData 回填数据;类型/子类型联动;备注通过开关控制显隐;提交走 api。

页面加载后自动回填数据(模拟 500ms 接口延迟);修改后点保存触发提交(模拟 600ms 接口);姓名字段下方有 extra slot 实时展示当前值。
vue
<template>
  <ProForm ref="formRef" :config="formConfig" @submit="onSubmit">
    <template #form-extra-name="{ formData }">
      <span style="color: #909399">当前:{{ formData?.name || '未填写' }}</span>
    </template>
  </ProForm>
</template>

<script setup>
import { getUserInfo, updateUserInfo } from '@/api/user'

const formConfig = {
  labelWidth: '90px',
  span: 12,
  params: {},
  model: { name: '', status: 1, type: '', subType: '', enableRemark: false, remark: '' },
  // 挂载时自动请求并回填
  fetchInitialData: async (params) => {
    const res = await getUserInfo(params)
    return res.data
  },
  api: async (data) => updateUserInfo(data),
  fields: [
    { label: '姓名', key: 'name', component: 'input', extra: 'slot',
      rules: [{ required: true, message: '请输入姓名' }] },
    { label: '状态', key: 'status', component: 'select',
      options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }] },
    { 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) => d.type === 'A'
        ? [{ label: 'A1', value: 'A1' }, { label: 'A2', value: 'A2' }]
        : [{ label: 'B1', value: 'B1' }, { label: 'B2', value: 'B2' }] },
    { label: '填写备注', key: 'enableRemark', component: 'switch' },
    { label: '备注', key: 'remark', component: 'textarea', rows: 3, span: 24,
      visible: (d) => d.enableRemark === true }
  ],
  footer: { submitText: '保存', showReset: true, align: 'left' }
}

function onSubmit(res, formData) {
  console.log('保存成功', formData)
}
</script>

长表单校验失败自动滚动 ​

用于验证字段较多、表单内容区域出现滚动条时,点击提交后是否会自动滚动到第一个必填错误项。

先手动把表单滚到最底部,然后直接点击“提交测试”;顶部必填项为空时,会使用 Element Plus 的 scroll-to-error / scrollToField 自动滚回错误字段。
vue
<template>
  <div class="form-scroll-box">
    <ProForm :config="formConfig" />
  </div>
</template>

<script setup>
const fillerFields = Array.from({ length: 24 }, (_, index) => ({
  label: `普通字段 ${index + 1}`,
  key: `field${index + 1}`,
  component: 'input'
}))

const formConfig = {
  labelWidth: '110px',
  span: 24,
  model: {
    requiredName: '',
    requiredCode: '',
    ...Object.fromEntries(fillerFields.map((field) => [field.key, '']))
  },
  formAttrs: {
    scrollToError: true,
    scrollIntoViewOptions: { behavior: 'smooth', block: 'center', inline: 'nearest' }
  },
  fields: [
    {
      label: '顶部必填名称',
      key: 'requiredName',
      component: 'input',
      rules: [{ required: true, message: '请输入顶部必填名称', trigger: 'blur' }]
    },
    {
      label: '顶部必填编码',
      key: 'requiredCode',
      component: 'input',
      rules: [{ required: true, message: '请输入顶部必填编码', trigger: 'blur' }]
    },
    ...fillerFields
  ],
  footer: { submitText: '提交测试', showReset: true }
}
</script>

<style scoped>
.form-scroll-box {
  height: 420px;
  overflow: hidden;
}
.form-scroll-box :deep(.pro-form) {
  height: 100%;
}
</style>

与 ProTable 联动(弹窗模式) ​

通过 form-config 传入 ProTable,内部自动管理弹层开关、新增/编辑模式切换:

vue
<template>
  <pro-table
    :search-config="searchConfig"
    :table-config="tableConfig"
    :form-config="formConfig"
  />
</template>

<script setup>
import { reactive } from 'vue'
import { getUserList, getUserDetail, saveUser, deleteUser } from '@/api/user'

const searchConfig = reactive({
  model: { name: '', status: '' },
  fields: [
    { label: '姓名', key: 'name', component: 'input' },
    { label: '状态', key: 'status', component: 'select',
      options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }] }
  ]
})

const tableConfig = reactive({
  requestConfig: { api: getUserList },
  columns: [
    { label: '姓名', key: 'name' },
    { label: '状态', key: 'status',
      tag: { map: { 1: '启用', 0: '禁用' }, type: { 1: 'success', 0: 'danger' } } },
    { label: '创建时间', key: 'createTime', width: 160 }
  ],
  deleteConfig: { api: deleteUser, idField: 'id' }
})

const formConfig = reactive({
  mode: 'dialog',
  width: '500px',
  model: { name: '', status: 1, type: 'A', subType: '' },
  fields: [
    { label: '姓名', key: 'name', component: 'input',
      rules: [{ required: true, message: '请输入姓名' }] },
    { label: '状态', key: 'status', component: 'select',
      options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }] },
    { 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) => d.type === 'A'
        ? [{ label: 'A1', value: 'A1' }, { label: 'A2', value: 'A2' }]
        : [{ label: 'B1', value: 'B1' }, { label: 'B2', value: 'B2' }] }
  ],
  add: { title: '新增用户', api: saveUser },
  edit: {
    title: '编辑用户',
    api: saveUser,
    fetchInitialData: async (row) => {
      const res = await getUserDetail(row.id)
      return res.data
    }
  }
})
</script>

可按需查阅 ProForm 表单、字段配置、上传配置。