XinForm 动态表单

XinForm 是基于 JSON 配置驱动的动态表单组件,支持三种展示模式(普通表单、弹窗表单、抽屉表单),并提供字段联动、栅格布局、自定义渲染等高级功能。

三种布局模式

模式说明
Form普通表单模式,直接渲染在当前页面
ModalForm弹窗表单模式,通过触发器打开 Modal 弹窗
DrawerForm抽屉表单模式,通过触发器打开 Drawer 抽屉

基础用法

Form 模式

import XinForm from '@/components/XinForm';
import type { XinFormRef } from '@/components/XinForm';

const columns = [
  { dataIndex: 'name', title: '名称', valueType: 'text' },
  { dataIndex: 'email', title: '邮箱', valueType: 'text' },
  { dataIndex: 'status', title: '状态', valueType: 'select', fieldProps: {
    options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }]
  }},
];

<XinForm
  columns={columns}
  onFinish={async (values) => {
    console.log(values);
  }}
/>

ModalForm 模式

<XinForm
  layoutType="ModalForm"
  columns={columns}
  trigger={<Button type="primary">新建</Button>}
  modalProps={{ title: '创建用户', width: 600 }}
  onFinish={async (values) => {
    await createUser(values);
  }}
/>

DrawerForm 模式

<XinForm
  layoutType="DrawerForm"
  columns={columns}
  trigger={<Button>编辑</Button>}
  drawerProps={{ title: '编辑用户', width: 500 }}
  onFinish={async (values) => {
    await updateUser(values);
  }}
/>

Grid 栅格布局

开启 grid 模式后,表单项会按照 Col 布局排列,默认每项占 12 格(半行)。

<XinForm
  grid
  columns={columns}
  rowProps={{ gutter: 16 }}
  colProps={{ span: 8 }}  // 全局默认每项占 8 格(一行三个)
/>

也可以为单个字段指定 colProps,会与全局 colProps 合并:

const columns = [
  { dataIndex: 'name', title: '名称', colProps: { span: 24 } },  // 整行
  { dataIndex: 'email', title: '邮箱', colProps: { span: 12 } },
  { dataIndex: 'phone', title: '电话', colProps: { span: 12 } },
];

字段依赖(联动)

通过 dependency 配置实现字段之间的联动,支持显示/隐藏、启用/禁用和动态属性。

const columns = [
  { dataIndex: 'type', title: '类型', valueType: 'select', fieldProps: {
    options: [
      { label: '文本', value: 'text' },
      { label: '数字', value: 'number' },
    ]
  }},
  {
    dataIndex: 'value',
    title: '值',
    valueType: 'text',
    dependency: {
      dependencies: ['type'],
      // 仅在类型为 text 时显示
      visible: (values) => values.type === 'text',
      // 动态修改 fieldProps
      fieldProps: (values) => ({
        placeholder: values.type === 'text' ? '请输入文本' : '请输入数字',
      }),
    },
  },
];

FieldDependency 配置

属性类型说明
dependencies(keyof T)[]依赖的字段名数组
visible(values: Partial<T>) => boolean根据依赖值判断是否显示
disabled(values: Partial<T>) => boolean根据依赖值判断是否禁用
fieldProps(values: Partial<T>) => Record<string, any>根据依赖值动态修改 fieldProps

FormColumn 字段配置

每个 columns 项除支持 Ant Design Form.Item 的全部属性外,还扩展了以下属性:

属性类型必填说明
dataIndexstring | number | (string | number)[]字段名,对应表单值的 key
valueTypeFieldValue字段类型,决定渲染的输入组件
titlestring字段标签,同时作为 placeholder 的默认值
fieldPropsobject传给输入组件的属性,类型根据 valueType 自动推断
fieldRender(form: FormInstance) => ReactNode自定义字段渲染函数,会替换默认的 FieldRender
colPropsColProps栅格布局时该字段的列属性,会与全局 colProps 合并
dependencyFieldDependency字段依赖配置

支持的 valueType

valueType渲染组件说明
textInput文本输入
passwordInput.Password密码输入
textareaInput.TextArea多行文本
digitInputNumber数字输入
moneyInputNumber金额输入
selectSelect下拉选择
treeSelectTreeSelect树形选择
cascaderCascader级联选择
radioRadio.Group单选框组
radioButtonRadio.Group (button)单选按钮组
checkboxCheckbox.Group多选框组
switchSwitch开关
rateRate评分
sliderSlider滑动条
dateDatePicker日期选择
dateTimeDatePicker (showTime)日期时间选择
dateRangeDatePicker.RangePicker日期范围
timeTimePicker时间选择
timeRangeTimePicker.RangePicker时间范围
weekDatePicker (week)周选择
monthDatePicker (month)月选择
quarterDatePicker (quarter)季度选择
yearDatePicker (year)年选择
imageImageUploader图片上传
colorColorPicker颜色选择
iconIconSelector图标选择
userUserSelector用户选择

操作栏配置(submitter)

隐藏操作栏

<XinForm
  columns={columns}
  submitter={{ render: false }}
/>

自定义按钮文本

<XinForm
  columns={columns}
  submitter={{
    submitText: '保存',
    resetText: '清空',
    closeText: '取消',
  }}
/>

自定义按钮属性

<XinForm
  columns={columns}
  submitter={{
    submitButtonProps: { danger: true, disabled: true },
    resetButtonProps: { type: 'dashed' },
  }}
/>

完全自定义操作栏

<XinForm
  columns={columns}
  submitter={{
    render: (buttons, formRef) => (
      <Space>
        {buttons.submit}
        <Button onClick={() => console.log('草稿')}>保存草稿</Button>
        {buttons.reset}
      </Space>
    ),
  }}
/>

SubmitterProps 配置

属性类型说明
renderfalse | ((buttons, formRef) => ReactNode)设为 false 隐藏操作栏,或传入自定义渲染函数
submitTextstring | ReactNode提交按钮文本,默认 t('xinForm.submit')
resetTextstring | ReactNode重置按钮文本,默认 t('xinForm.reset')
closeTextstring | ReactNode关闭按钮文本,默认 t('xinForm.cancel')
submitButtonPropsButtonProps提交按钮的额外属性
resetButtonPropsButtonProps重置按钮的额外属性
closeButtonPropsButtonProps关闭按钮的额外属性

注意:Form 模式下不显示关闭按钮;ModalForm / DrawerForm 会显示关闭按钮。

XinFormRef 实例方法

通过 formRef 可以获取表单实例,支持 Ant Design Form 全部方法,并扩展了以下方法:

方法说明
open()打开弹窗/抽屉(仅 ModalForm / DrawerForm)
close()关闭弹窗/抽屉(仅 ModalForm / DrawerForm)
isOpen()获取弹窗/抽屉的打开状态
setLoading(loading: boolean)设置提交按钮的加载状态
import { useRef } from 'react';
import type { XinFormRef } from '@/components/XinForm';

const formRef = useRef<XinFormRef>(null);

// 在外部打开弹窗
<Button onClick={() => formRef.current?.open()}>打开表单</Button>

<XinForm
  formRef={formRef}
  layoutType="ModalForm"
  columns={columns}
/>

// 获取表单实例方法
const values = formRef.current?.getFieldsValue();
formRef.current?.setFieldsValue({ name: '默认名称' });
formRef.current?.setLoading(true);

XinFormProps 完整属性

属性类型默认值说明
columnsFormColumn<T>[]-表单列配置(必填)
layoutType'Form' | 'ModalForm' | 'DrawerForm''Form'表单布局类型
gridbooleanfalse是否使用栅格布局
rowPropsRowProps-开启 grid 时传递给 Row 的属性
colPropsColProps{ span: 12 }传递给每个表单项 Col 的默认属性
onFinish(values: T) => Promise<boolean | void>-表单提交回调
formRefRefObject<XinFormRef>-表单实例引用
formFormInstance<T>-外部传入的表单实例
modalPropsModalProps-ModalForm 时的弹窗配置(不含 open)
drawerPropsDrawerProps-DrawerForm 时的抽屉配置(不含 open)
triggerReactNode-打开弹窗/抽屉的触发器
submitterSubmitterProps-操作栏配置

同时继承 FormProps<T>onFinish 外的全部属性,可直接传入 initialValueslabelCol 等。

完整示例

以下示例展示了创建用户的弹窗表单,包含栅格布局和字段联动:

import { useRef } from 'react';
import XinForm from '@/components/XinForm';
import type { XinFormRef } from '@/components/XinForm';
import { Button, message } from 'antd';

const userColumns = [
  {
    dataIndex: 'username',
    title: '用户名',
    valueType: 'text',
    colProps: { span: 12 },
    fieldProps: { maxLength: 50 },
    rules: [{ required: true, message: '请输入用户名' }],
  },
  {
    dataIndex: 'email',
    title: '邮箱',
    valueType: 'text',
    colProps: { span: 12 },
    rules: [
      { required: true, message: '请输入邮箱' },
      { type: 'email', message: '邮箱格式不正确' },
    ],
  },
  {
    dataIndex: 'role',
    title: '角色',
    valueType: 'select',
    colProps: { span: 12 },
    fieldProps: {
      options: [
        { label: '管理员', value: 'admin' },
        { label: '普通用户', value: 'user' },
      ],
    },
  },
  {
    dataIndex: 'role_extra',
    title: '管理员备注',
    valueType: 'textarea',
    colProps: { span: 24 },
    dependency: {
      dependencies: ['role'],
      visible: (values) => values.role === 'admin',
    },
  },
];

function UserCreate() {
  const formRef = useRef<XinFormRef>(null);

  const handleCreate = async (values: any) => {
    const result = await createUser(values);
    if (result) {
      message.success('创建成功');
      return true;  // 返回 true 会关闭弹窗
    }
    return false;
  };

  return (
    <>
      <Button type="primary" onClick={() => formRef.current?.open()}>
        新建用户
      </Button>

      <XinForm
        formRef={formRef}
        layoutType="DrawerForm"
        grid
        rowProps={{ gutter: 16 }}
        columns={userColumns}
        onFinish={handleCreate}
        drawerProps={{
          title: '新建用户',
          width: 600,
        }}
        submitter={{
          submitText: '创建',
          resetText: '清空',
        }}
      />
    </>
  );
}