ant desgn react
一、基础使用
1. 文件夹结构介绍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ├── config # umi 配置,包含路由,构建等配置 ├── mock # 本地模拟数据 ├── public │ └── favicon.png # Favicon ├── src │ ├── assets # 本地静态资源 │ ├── e2e # 集成测试用例 │ ├── layouts # 通用布局 │ ├── models # 全局 dva model │ ├── pages # 业务页面入口 │ ├── services # 后台接口服务 │ ├── shared/etc_bfplus # 公共组件及工具库 │ ├── locales # 国际化资源 │ ├── global.less # 全局样式 │ └── global.tsx # 全局页面 ├── tests # 测试工具 ├── README.md └── package.json
|
2. 项目启动
在 terminal 执行命令(默认开启 mock)
本地访问地址为http://localhost:8005/user/login
如不需要 mock,执行命令
本地启动的端口默认是 8005,如果需要修改的话,更改.env 文件
3. 本地调试(proxy 的反向代理)
- 打开 config/config.ts,对应修改不同的接口服务所代理的服务器域名,如修改‘/api’前缀的接口服务为自己本地 IP,直接修改 target 的值

4. 页面代码结构推荐(请遵循此守则开发)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| src ├── components └── pages ├── Welcome | ├── components | ├── index.tsx | └── index.less ├── Order | ├── index.tsx | └── index.less ├── user | ├── components | ├── Login | ├── Register | └── util.ts └── *
|
二、页面开发
1. 快速创建 CRUD 页面
- 创建路由组件
- 要生成模块,模块下包含多个路由组件,在 terminal 执行命令 npm run temp 目录(强烈要求这种方式)
1 2
| eg: npm run temp test/Table
|
会在 src/pages 目录下创建 test 文件夹,内包含 Table 文件夹,文件夹里面包含 index.tsx 和 d.ts 两个文件。
b. 要生成单路由组件,在 terminal 执行命令 npm run temp 组件名
会在 src/pages 目录下创建 Order 文件夹,内包含 index.tsx 以及 d.ts 两个文件,d.ts 文件是该模块的 typescript 描述文件,用来指定对象的类型。
- 将文件加入菜单和路由
a. 在 config/routes 文件夹内创建一个有关该模块的所有路由文件,命名规则是模块名.routes.ts,比如售后模块,after-sale.routes.ts,像上面我们新增的 test 模块,我们就创建一个 test.routes.ts 文件。
1 2 3 4 5 6 7 8 9 10 11 12 13
| export default { path: "/test", component: "../layouts/BasicLayout", routes: [ { path: "/test/table", name: "表格", component: "./test/Table/index", }, ], };
|
b. 创建完路由文件之后,要在 config/routes.js 文件中引入


1 2
| import testRoutes from "./routes/test.routes";
|
- 定义接口请求文件
在 services 文件夹创建一个该模块的接口请求文件,如 test.ts,用于该模块的所有请求。
1 2 3 4 5 6 7
| import request from "@bfp/utils/request"; import downloadData from "@bfp/utils/downLoad";
export const apiTestGetList = async (data: any): Promise<any> => request("/api/template/getList", { data, method: "POST" });
|
创建完 test.ts 之后,在 services/index.ts 文件中引入该模块接口文件
- 打开浏览器(已登录状态),访问 http://localhost:8005/test/table,可以看到已经能成功访问该页面了

2. 介绍 CRUD 页面中的自定义组件 Grid 用法
1
| <Grid />组件由自定义组件<SearchForm />和<TableComponent />两部分组成
|

该组件暴露两个实例,一个是表单的实例 form,一个是表格的实例 tableCom,当需要操作该表单或者表格的一些方法,可通过这两个实例操作!
1
| eg: const form = $table.current._form
|
当定义columns
的时候,设置query
属性,Grid 会根据query
的定义自动生成表单,query 对应的 type 配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| type QueryType = { label?: string;
name: string;
type: "select" | "datePicker";
render: () => React.ReactNode;
colProps: ColProps;
formItemProps: FormItemProps;
selectConfig?: { label?: string;
value?: string;
options?: | Promise<object | { key: string; value: string | number }[]> | object | { key: string; value: string | number }[];
showAll?: Boolean; } & SelectProps<string | number>;
pickerConfig?: RangePickerProps;
elementProps?: any; };
|
页面都自动生成默认示例了,可根据需求自行调整:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| const columns = [ { title: "常规字段", dataIndex: "field1", }, { title: "文本框查询", dataIndex: "field2", query: true, }, { title: "下拉框查询", dataIndex: "field3", query: { type: "select", selectConfig: { options: testOptions, showAll: true, }, }, }, { title: "日期期间查询", dataIndex: "field4", query: { type: "datePicker", name: "startField4-endField4", }, }, { title: "表单有表格隐藏", dataIndex: "field5", hideInTable: true, query: true, }, { title: "操作", dataIndex: "opt", fixed: "right", render: () => ( <Space> <Button type="primary">编辑</Button> <Button type="primary" danger onClick={() => onDelete()}> 删除 </Button> </Space> ), }, ];
|
该组件同时暴露了两个操作表格的函数,一个是查询表格 handleTableChange(),一个是导出表格 handleExportTable(),当执行了新增或者编辑之后需要重刷新表格时,可执行如图代码:

1
| $table.current.handleTableChange();
|
三、数据及状态管理
1. 常用 hooks
1 2 3
| eg:
const [modalVisible, setModalVisible] = useState(false);
|
1 2 3 4 5 6 7 8 9
| eg: useEffect(() => { async function fetchData() { const { data } = await getIncomeTypesEnums(); setEnums(data); }
fetchData(); }, []);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| export const GridContext = React.createContext();
export default () => { <GridContext.Provider value={enums}> <Grid ref={childRef} renderForm={onSearchForm} columns={columns} getDataApi={getTypeManageList} > <div style={{ marginBottom: 20 }}> <Button type="primary" onClick={() => { setAddVisible(true), setCurrentDetail({}); }} > 添加 </Button> </div> </Grid> </GridContext.Provider>; };
import { GridContext } from "../index";
const { cardCategoryEnumMap } = useContext(GridContext);
|
2. 简易数据流交互
中后台场景下,绝大多数页面的数据流转都是在当前页完成,在页面挂载的时候请求后端接口获取并消费,这种场景下并不需要复杂的数据流方案。但是也存在需要全局共享的数据,如用户的角色权限信息或者其他一些页面间共享的数据。为了实现在多个页面中的数据共享,以及一些业务可能需要的简易的数据流管理的场景,我们基于 hooks & umi 插件实现了一种轻量级的全局数据共享的方案。
a. 如何使用
在 src/models 目录下新建文件,文件名会成为 model 的 namespace。
1
| eg. demo.ts 的 namespace 是 demo
|
一个 model 的内容需要是一个标准的 JavaScript function,并被默认导出,可以在 function 中使用 hooks.
例如下面的例子就是一个合法的 model:
1 2
| export default () => "Hello World";
|
在实际使用场景中,model 可以包含其他 hooks,例如下面的计数器的例子:
1 2 3 4 5 6 7 8 9
| import { useState, useCallback } from "react";
export default () => { const [counter, setCounter] = useState(0); const increment = useCallback(() => setCounter((c) => c + 1), []); const decrement = useCallback(() => setCounter((c) => c - 1), []); return { counter, increment, decrement }; };
|
b. 使用 model
在代码中使用 model,需要从 umi 中导出 useModel。useModel 是一个 React Custom Hook,传入 namespace 即可获取对应 model 的返回值。
1 2 3 4 5 6
| import { useModel } from "umi";
export default () => { const message = useModel("demo"); return <div>{message}</div>; };
|
上述例子中的 message 会包含 demo model 的返回值,即:Hello World;
3. 如何进行 mock 数据调试
在 mock 文件夹下新建一个关于该模块的 mock 请求文件,如 user.ts,如果执行启动命令 npm run start 默认开启 mock 接口优先,如果 mock 文件夹下有定义改接口请求,则走这里定义的返回数据,如果没有定义则请求真实的 service 请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 'POST /api/template/getList': (req: Request, res: Response) => { res.status(200).send({ code: 0, data: { current: 1, orders: [], pages: 0, records: [ { field1: 't1', field2: 't2', field3: 't3', field4: '2020-02-11', field5: 't5' }, ], searchCount: true, size: 10, total: 0 }, msg: '成功操作' }); },
|