#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 的全部属性外,还扩展了以下属性:
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
| dataIndex | string | number | (string | number)[] | 是 | 字段名,对应表单值的 key |
| valueType | FieldValue | 否 | 字段类型,决定渲染的输入组件 |
| title | string | 否 | 字段标签,同时作为 placeholder 的默认值 |
| fieldProps | object | 否 | 传给输入组件的属性,类型根据 valueType 自动推断 |
| fieldRender | (form: FormInstance) => ReactNode | 否 | 自定义字段渲染函数,会替换默认的 FieldRender |
| colProps | ColProps | 否 | 栅格布局时该字段的列属性,会与全局 colProps 合并 |
| dependency | FieldDependency | 否 | 字段依赖配置 |
#支持的 valueType
| valueType | 渲染组件 | 说明 |
|---|---|---|
| text | Input | 文本输入 |
| password | Input.Password | 密码输入 |
| textarea | Input.TextArea | 多行文本 |
| digit | InputNumber | 数字输入 |
| money | InputNumber | 金额输入 |
| select | Select | 下拉选择 |
| treeSelect | TreeSelect | 树形选择 |
| cascader | Cascader | 级联选择 |
| radio | Radio.Group | 单选框组 |
| radioButton | Radio.Group (button) | 单选按钮组 |
| checkbox | Checkbox.Group | 多选框组 |
| switch | Switch | 开关 |
| rate | Rate | 评分 |
| slider | Slider | 滑动条 |
| date | DatePicker | 日期选择 |
| dateTime | DatePicker (showTime) | 日期时间选择 |
| dateRange | DatePicker.RangePicker | 日期范围 |
| time | TimePicker | 时间选择 |
| timeRange | TimePicker.RangePicker | 时间范围 |
| week | DatePicker (week) | 周选择 |
| month | DatePicker (month) | 月选择 |
| quarter | DatePicker (quarter) | 季度选择 |
| year | DatePicker (year) | 年选择 |
| image | ImageUploader | 图片上传 |
| color | ColorPicker | 颜色选择 |
| icon | IconSelector | 图标选择 |
| user | UserSelector | 用户选择 |
#操作栏配置(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 配置
| 属性 | 类型 | 说明 |
|---|---|---|
| render | false | ((buttons, formRef) => ReactNode) | 设为 false 隐藏操作栏,或传入自定义渲染函数 |
| submitText | string | ReactNode | 提交按钮文本,默认 t('xinForm.submit') |
| resetText | string | ReactNode | 重置按钮文本,默认 t('xinForm.reset') |
| closeText | string | ReactNode | 关闭按钮文本,默认 t('xinForm.cancel') |
| submitButtonProps | ButtonProps | 提交按钮的额外属性 |
| resetButtonProps | ButtonProps | 重置按钮的额外属性 |
| closeButtonProps | ButtonProps | 关闭按钮的额外属性 |
注意: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 完整属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| columns | FormColumn<T>[] | - | 表单列配置(必填) |
| layoutType | 'Form' | 'ModalForm' | 'DrawerForm' | 'Form' | 表单布局类型 |
| grid | boolean | false | 是否使用栅格布局 |
| rowProps | RowProps | - | 开启 grid 时传递给 Row 的属性 |
| colProps | ColProps | { span: 12 } | 传递给每个表单项 Col 的默认属性 |
| onFinish | (values: T) => Promise<boolean | void> | - | 表单提交回调 |
| formRef | RefObject<XinFormRef> | - | 表单实例引用 |
| form | FormInstance<T> | - | 外部传入的表单实例 |
| modalProps | ModalProps | - | ModalForm 时的弹窗配置(不含 open) |
| drawerProps | DrawerProps | - | DrawerForm 时的抽屉配置(不含 open) |
| trigger | ReactNode | - | 打开弹窗/抽屉的触发器 |
| submitter | SubmitterProps | - | 操作栏配置 |
同时继承
FormProps<T>除onFinish外的全部属性,可直接传入initialValues、labelCol等。
#完整示例
以下示例展示了创建用户的弹窗表单,包含栅格布局和字段联动:
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: '清空',
}}
/>
</>
);
}