Antd Pro Components的基本使用

3,738 阅读7分钟

1. 关于 ant-pro components

ProComponents 是基于 Ant Design 而开发的模板组件,提供了更高级别的抽象支持,开箱即用。可以显著地提升制作 CRUD 页面的效率,更加专注于页面本身。

ant-pro components 本身也是一个monorepo仓库,如图:

image.png

其中,每一个文件夹都代表一个组件,这也就意味着,ProComponents 每一个组件都是一个独立的包。

  • ProLayout 解决布局的问题,提供开箱即用的菜单和面包屑功能
  • ProTable 表格模板组件,抽象网络请求和表格格式化
  • ProForm 表单模板组件,预设常见布局和行为
  • ProCard 提供卡片切分以及栅格布局能力
  • ProDescriptions 定义列表模板组件,ProTable 的配套组件
  • ProSkeleton 页面级别的骨架屏
  • ProSkeleton 表单项,集成了常用的表单项,可以把他们当成一个 FormItem来使用

2. 快速搭建通用页面

2.1 搜索项 + 表格

ProTable 在 antd 的 Table 上进行了一层封装,支持了一些预设,并且封装了一些行为。这里只列出与 antd Table 不同的 API。

2.1.1 request

request 是 ProTable 最重要的 API,request 会接收一个对象。对象中必须要有 data 和 success,如果需要手动分页 total 也是必需的。request 会接管 loading 的设置,同时在查询表单查询时和 params 参数发生修改时重新执行。同时查询表单的值和 params 参数也会带入。以下是一个例子

<ProTable<DataType, Params>
  // params 是需要自带的参数
  // 这个参数优先级更高,会覆盖查询表单的参数
  params={params}
  request={async (
    // 第一个参数 params 查询表单和 params 参数的结合
    // 第一个参数中一定会有 pageSize 和  current ,这两个参数是 antd 的规范
    params: T & {
      pageSize: number;
      current: number;
    },
    sort,
    filter,
  ) => {
    // 这里需要返回一个 Promise,在返回之前你可以进行数据转化
    // 如果需要转化参数可以在这里进行修改
    const msg = await myQuery({
      page: params.current,
      pageSize: params.pageSize,
    });
    return {
      data: msg.result,
      // success 请返回 true,
      // 不然 table 会停止解析数据,即使有数据
      success: boolean,
      // 不传会使用 data 的长度,如果是分页一定要传
      total: number,
    };
  }}
/>

2.1.2 ActionRef 手动触发

有时我们要手动触发 table 的 reload 等操作,可以使用 actionRef

interface ActionType {
  reload: (resetPageIndex?: boolean) => void;
  reloadAndRest: () => void;
  reset: () => void;
  clearSelected?: () => void;
  startEditable: (rowKey: Key) => boolean;
  cancelEditable: (rowKey: Key) => boolean;
}
const ref = useRef<ActionType>();
<ProTable actionRef={ref} />;

// 刷新
ref.current.reload();

// 刷新并清空,页码也会重置,不包括表单
ref.current.reloadAndRest();

// 重置到默认值,包括表单
ref.current.reset();

// 清空选中项
ref.current.clearSelected();

// 开始编辑
ref.current.startEditable(rowKey);

// 结束编辑
ref.current.cancelEditable(rowKey);

2.2 表单

ProForm 在原来的 Form 的基础上增加了一些语法糖和更多的布局设置,帮助我们快速地开发一个表单,同时添加了一些默认行为,让我们的表单默认好用。当你想快速实现一个表单但不想花太多时间去布局时 ProForm 是最好的选择。

ProForm 是基于 antd Form 的可降级封装,与 antd 功能完全对齐,但是在其之上还增加一些预设行为和多种布局。这些布局之间可以无缝切换,并且拥有公共的 API。

2.2.1 ProForm表单

ProForm 封装了很多常见的表单逻辑和布局,学习成本相对较低。团队成员只需要了解一些简单的配置项,就可以快速上手并搭建出表单页面。这对于新手开发者或者对表单开发经验较少的团队来说,可以降低学习门槛,提高开发效率。

  1. 数据获取:- 支持数据同步和异步处理:可以通过配置 request 属性实现异步数据提交。
          <ProFormSelect
            width="md"
           valueEnum={{
              red: 'Red',
              green: 'Green',
              blue: 'Blue',
            }}
            fieldProps={{
              labelInValue: true,
            }}
            request={async () => [
              { label: '全部', value: 'all' },
              { label: '未解决', value: 'open' },
              { label: '已解决', value: 'closed' },
              { label: '解决中', value: 'processing' },
            ]}
            name="useMode"
            label="合同约定生效方式"
          />

2. params:配合 request 属性使用,用于传递请求所需的参数。当表单初始化请求数据或者提交数据时,这些参数会被发送到服务器。 3. submitter 用于配置表单提交按钮的属性和行为,如按钮的文本、样式、是否显示等。可以通过 submitter 属性快速定制提交按钮,而在 antd Form 中需要手动编写提交按钮的代码。 4. ProFormDependency 数据联动:procomponents.ant.design/components/… 5. 还有一些其他的属性方便表单的开发,详细的文档可在官网查看:procomponents.ant.design/components/…

2.3 Schema Form - JSON 表单

chemaForm 是根据 JSON Schema 来生成表单的工具。SchemaForm 会根据 valueType 来映射成不同的表单项

对于复杂的表单而言,虽然JSON配置化的效率看起来很高,实际中对于查找问题还是有一些不方便的地方,例如关键字的查找可能会定

import type { ProFormColumnsType } from '@ant-design/pro-components';
import {
  BetaSchemaForm,
  ProForm,
  ProFormSelect,
  ProFormText,
} from '@ant-design/pro-components';

const valueEnum = {
  all: { text: '全部', status: 'Default' },
  open: {
    text: '未解决',
    status: 'Error',
  },
  closed: {
    text: '已解决',
    status: 'Success',
    disabled: true,
  },
  processing: {
    text: '解决中',
    status: 'Processing',
  },
};

type DataItem = {
  name: string;
  state: string;
};

const columns: ProFormColumnsType<DataItem>[] = [
  {
    title: '标题',
    dataIndex: 'title',
    formItemProps: {
      rules: [
        {
          required: true,
          message: '此项为必填项',
        },
      ],
    },
    width: 'm',
  },
  {
    title: '状态',
    dataIndex: 'state',
    valueType: 'select',
    valueEnum,
    width: 'm',
  },
];

export default () => {
  return (
    <ProForm>
      <h1>ProForm </h1>
      <ProFormText name="username" />
      <ProFormSelect
        name="select-multiple"
        label="多选"
        valueEnum={{
          red: 'Red',
          green: 'Green',
          blue: 'Blue',
        }}
        fieldProps={{
          mode: 'multiple',
        }}
        placeholder="Please select favorite colors"
        rules={[          {            required: true,            message: 'Please select your favorite colors!',            type: 'array',          },        ]}
      />
      <h1>表单1 </h1>
      <BetaSchemaForm<DataItem> layoutType="Embed" columns={columns} />
      <h1>表单2</h1>
      <BetaSchemaForm<DataItem>
        layoutType="Embed"
        columns={[          {            title: '创建时间',            key: 'showTime',            dataIndex: 'createName',            valueType: 'date',          },          {            title: '分组',            valueType: 'group',            columns: [              {                title: '状态',                dataIndex: 'groupState',                valueType: 'select',                width: 'xs',                valueEnum,              },              {                title: '标题',                width: 'md',                dataIndex: 'groupTitle',                formItemProps: {                  rules: [                    {                      required: true,                      message: '此项为必填项',                    },                  ],
                },
              },
            ],
          },
        ]}
      />
    </ProForm>
  );
};

procomponents.ant.design/components/… 示例

import type { ProFormColumnsType } from '@ant-design/pro-components';
import {
  BetaSchemaForm,
  ProForm,
  ProFormSelect,
  ProFormText,
} from '@ant-design/pro-components';

const valueEnum = {
  all: { text: '全部', status: 'Default' },
  open: {
    text: '未解决',
    status: 'Error',
  },
  closed: {
    text: '已解决',
    status: 'Success',
    disabled: true,
  },
  processing: {
    text: '解决中',
    status: 'Processing',
  },
};

type DataItem = {
  name: string;
  state: string;
};

const columns: ProFormColumnsType<DataItem>[] = [
  {
    title: '标题',
    dataIndex: 'title',
    formItemProps: {
      rules: [
        {
          required: true,
          message: '此项为必填项',
        },
      ],
    },
    width: 'm',
  },
  {
    title: '状态',
    dataIndex: 'state',
    valueType: 'select',
    valueEnum,
    width: 'm',
  },
];

export default () => {
  return (
    <ProForm>
      <h1>ProForm </h1>
      <ProFormText name="username" />
      <ProFormSelect
        name="select-multiple"
        label="多选"
        valueEnum={{
          red: 'Red',
          green: 'Green',
          blue: 'Blue',
        }}
        fieldProps={{
          mode: 'multiple',
        }}
        placeholder="Please select favorite colors"
        rules={[          {            required: true,            message: 'Please select your favorite colors!',            type: 'array',          },        ]}
      />
      <h1>表单1 </h1>
      <BetaSchemaForm<DataItem> layoutType="Embed" columns={columns} />
      <h1>表单2</h1>
      <BetaSchemaForm<DataItem>
        layoutType="Embed"
        columns={[          {            title: '创建时间',            key: 'showTime',            dataIndex: 'createName',            valueType: 'date',          },          {            title: '分组',            valueType: 'group',            columns: [              {                title: '状态',                dataIndex: 'groupState',                valueType: 'select',                width: 'xs',                valueEnum,              },              {                title: '标题',                width: 'md',                dataIndex: 'groupTitle',                formItemProps: {                  rules: [                    {                      required: true,                      message: '此项为必填项',                    },                  ],
                },
              },
            ],
          },
        ]}
      />
    </ProForm>
  );
};

3.ProFormFields 表单项

3.1ProFormFields 的布局

ProFormFields 可以包裹多个不同类型的表单项,以构建复杂的表单。以下示例展示了包含文本输入框、密码输入框和提交按钮的表单:

const ComplexForm = () => {
  return (
    <ProForm onFinish={(values) => console.log('表单提交值:', values)}>
      <ProFormFields>
        <ProFormText name="username" label="用户名" />
        <ProFormText.Password name="password" label="密码" />
      </ProFormFields>
      <ProForm.Submit />
    </ProForm>
  );
};
3.2 与数据请求结合

ProFormFields 可以与 ProForm 的 request 属性结合,实现表单数据的异步加载和提交。以下示例展示了如何在表单初始化时从服务器获取数据,并在表单提交时将数据发送到服务器:

import axios from 'axios';

const fetchData = async () => {
  const response = await axios.get('/api/user');
  return response.data;
};

const submitData = async (values) => {
  await axios.post('/api/user', values);
};

const FormWithRequest = () => {
  return (
    <ProForm request={fetchData} onFinish={submitData}>
      <ProFormFields>
        <ProFormText name="username" label="用户名" />
        <ProFormText name="email" label="邮箱" />
      </ProFormFields>
      <ProForm.Submit />
    </ProForm>
  );
};
3.3 与 Form.Item 的区别

3.1 代码简洁性

  • ProFormFields + ProForm 系列组件:ProFormFields 结合 ProForm 提供的各种表单组件(如 ProFormTextProFormSelect 等),代码更加简洁。例如,创建一个简单的文本输入框,只需要一行代码:
<ProFormText name="username" label="用户名" />
  • Form.Item + 原生表单控件:使用 Ant Design 的 Form.Item 时,需要手动包裹原生表单控件,代码相对繁琐。例如:
<Form.Item label="用户名" name="username">
<Input />
</Form.Item>

3.2 功能封装

  • ProFormFields:ProFormFields 及相关组件封装了许多常见的表单逻辑,如数据验证、数据获取和提交等。例如,通过 rules 属性可以轻松设置表单验证规则:
<ProFormText
  name="username"
  label="用户名"
  rules={[{ required: true, message: '请输入用户名' }]}
/>

<Form.Item
  label="用户名"
  name="username"
  rules={[{ required: true, message: '请输入用户名' }]}
>
  <Input />
</Form.Item>

虽然两者都能实现验证,但 ProForm 的方式更加简洁。

3.3 布局与样式

  • ProFormFields:ProForm 提供了统一的布局和样式设置,如 labelWidth 属性可以统一设置表单项标签的宽度,使表单布局更加整齐美观。
<ProForm labelWidth={100}>
  <ProFormFields>
    <ProFormText name="username" label="用户名" />
    <ProFormText name="email" label="邮箱" />
  </ProFormFields>
</ProForm>
  • Form.Item:使用 Form.Item 时,需要手动调整每个表单项的布局和样式,灵活性较高,但也增加了开发的复杂度。

3.4 高级功能

  • ProFormFields:支持许多高级功能,如数据字典、动态表单项等。例如,使用 options 属性可以快速设置下拉框的选项:
<ProFormSelect
  name="city"
  label="城市"
  options={[
    { label: '北京', value: 'beijing' },
    { label: '上海', value:'shanghai' },
  ]}
/>
  • Form.Item:实现类似的高级功能需要编写更多的代码和逻辑。
4. 总结

在 admin 管理系统中,几乎风格都是统一的,页面的样式、 布局、以及页面的功能都能达到antd-pro的要求。可实现页面的快速搭建以及功能的统一。官方文档也一直在更新中

参考文章: