Ant Design Pro 是蚂蚁金服团队在 Ant Design 的设计规范与组件库基础上推出的一套 React 实现的企业级中后台前端/设计解决方案
安装
方式一:直接 clone git 仓库
1 2
| $ git clone --depth=1 https: $ cd my-project
|
方式二:使用npm命令行工具
1 2 3
| $ npm install ant-design-pro-cli -g $ mkdir my-project && cd my-project $ pro new # 安装脚手架
|
目录结构
我们已经为你生成了一个完整的开发框架,提供了涵盖中后台开发的各类功能和坑位,下面是整个项目的目录结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ├── mock ├── public │ └── favicon.ico ├── src │ ├── assets │ ├── common │ ├── components │ ├── e2e │ ├── layouts │ ├── models │ ├── routes │ ├── services │ ├── utils │ ├── g2.js │ ├── theme.js │ ├── index.ejs │ ├── index.js │ ├── index.less │ └── router.js ├── tests ├── README.md └── package.json
|
本地开发
安装依赖。
如果网络状况不佳,可以使用
启动完成后会自动打开浏览器访问 http://localhost:8000,你看到下面的页面就代表成功了。
加页面
新建菜单栏标签
在\src\common\menu.js中加入我们的新标签。
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
| { name: 'dashboard', icon: 'dashboard', path: 'dashboard', children: [ { name: '分析页', path: 'analysis', }, { name: '监控页', path: 'monitor', }, { name: '工作台', path: 'workplace', }, { name: '测试页', path: 'test', }, ], },
|
新建页面
在src/routes 下新建 pages文件夹,里面再新建页面。newPage.js
1 2 3 4 5 6 7 8 9 10 11 12 13
| import React,{PureComponent} from 'react';
export default class Workplace extends PureComponent{ render(){ return( <view> <h1>Hello World</h1> </view> ) } }
|
新建该页面的路由
在\src\common\router.js的getRouterData中加入我们的页面。
1 2 3 4 5 6 7 8 9 10 11 12
| '/': { component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')), }, '/dashboard/analysis': { component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')), }, '/dashboard/monitor': { component: dynamicWrapper(app, ['monitor'], () => import('../routes/Dashboard/Monitor')), }, '/dashboard/test': { component: dynamicWrapper(app, [], () => import('../routes/pages/newPage')), },
|
至此,我们的页面已经可以展示了。
组件化模块
实际使用时如果控件重复我们可以写到组件里调用
新建组件
如下:
在src/components下新建一个 大写的文件夹名ImageWrapper,里面新建文件index.js index.less
index.js
1 2 3 4 5 6 7 8 9
| import React from 'react' import styles from './index.less'
export default ({src,desc,style})=>( <div styles={style} className={styles.imageWrapper}> <img src={src} alt="desc" className={styles.img}/> {desc && <div className={styles.desc}>{desc}</div>} </div> );
|
index.less
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| .imageWrapper { padding: 0 20px 8px; background: #f2f4f5; width: 400px; margin: 0 auto; text-align: center; }
.img { vertical-align: middle; max-width: calc(100% - 32px); margin: 2.4em 1em; box-shadow: 0 8px 20px rgba(143, 168, 191, 0.35); }
|
调用组件
在我之前新建的newPage.js中调用我们的组件
1 2 3 4 5 6 7 8 9 10 11 12 13
| import React,{PureComponent} from 'react'; import ImageWrapper from '../../components/ImageWrapper'
export default class Workplace extends PureComponent{ render(){ return( <view> <ImageWrapper src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1523969861626&di=514baab40d332e00c2eee8a5717a652a&imgtype=0&src=http%3A%2F%2Ftv06.tgbusdata.cn%2Fv2%2Fthumb%2Fjpg%2FMDA5QSw1ODAsMTAwLDQsMywxLC0xLDAscms1MA%3D%3D%2Fu%2Fwow.tgbus.com%2FUploadFiles_2396%2F201206%2F2012060410191894.jpg" desc="测试数据"></ImageWrapper> </view> ) } }
|
好了,调用正常吧。
数据交互
Ant Design Pro 是一套基于 React 技术栈的单页面应用,提供的是前端代码和本地模拟数据的开发模式,
通过 Restful API 的形式和任何技术栈的服务端应用一起工作。
前端请求流程
在 Ant Design Pro 中,一个完整的前端 UI 交互到服务端处理流程是这样的:
- UI 组件交互操作;
- 调用 model 的 effect;
- 调用统一管理的 service 请求函数;
- 使用封装的 request.js 发送请求;
- 获取服务端返回;
- 然后调用 reducer 改变 state;
- 更新 model。
从上面的流程可以看出,为了方便管理维护,统一的请求处理都放在 services
文件夹中,并且一般按照 model 维度进行拆分文件,如:
1 2 3 4
| services/ user.js api.js ...
|
其中,utils/request.js
是基于 fetch 的封装,便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。具体可以参看 request.js。
Ant Design Pro 直接沿用了 roadhog 中自带的 mock 功能,方便本地快速开发调试。
还是以之前的测试页面为例,我们为它新建一个测试请求:
新建一个dva model
在src/models 新建文件testdata.js
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
| import { queryProjectList} from '../services/api';
export default { namespace: 'testdata',
state: { testdata:{}, },
effects: { *fetchProject(_, { call, put }) { const response = yield call(queryProjectList); yield put({ type: 'saveProject', payload: response, }); }, },
reducers: { saveProject(state, action) { return { ...state, testdata: action.payload, }; }, }, };
|
其中queryProjectList是我们真正要发的请求方法
新建请求方法
在src/services/api.js中新建方法:
1 2 3
| export async function queryProjectList() { return request('/api/project'); }
|
request(‘/api/project’);就是实际的请求路径,是在本地调试代理下,所以请求最终会被mock到.roadhogrc.mock.js
新建测试请求数据
在.roadhogrc.mock.js中新建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 'GET /api/project' : { code: 0, content: [ { "create_time": "Tue, 12 Dec 2017 11:27:40 GMT", "create_user": "test1", "entry": 6, "project_key": "test1_app" }, { "create_time": "Tue, 12 Dec 2017 11:28:00 GMT", "create_user": "test2", "entry": 7, "project_key": "test2_app" } ] }
|
页面发请求
回到 之前新建的newPage.js
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
| import React,{PureComponent} from 'react'; import ImageWrapper from '../../components/ImageWrapper' import { connect } from 'dva';
@connect(({ testdata,loading }) => ({ testdata, loading: loading.effects['project/fetchProject'], }))
export default class Workplace extends PureComponent{ componentDidMount() { const { dispatch } = this.props; dispatch({ type: 'testdata/fetchProject', }); } render(){ const { testdata,loading } = this.props; return( <view> <ImageWrapper src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1523969861626&di=514baab40d332e00c2eee8a5717a652a&imgtype=0&src=http%3A%2F%2Ftv06.tgbusdata.cn%2Fv2%2Fthumb%2Fjpg%2FMDA5QSw1ODAsMTAwLDQsMywxLC0xLDAscms1MA%3D%3D%2Fu%2Fwow.tgbus.com%2FUploadFiles_2396%2F201206%2F2012060410191894.jpg" desc="测试数据"></ImageWrapper> <p>{testdata.testdata.content[0].create_user}</p> </view> ) } }
|
@connect 装饰器
首先的组件写法中调用了 dva 所封装的 react-redux 的 @connect 装饰器,用来接收绑定的 list 这个 model 对应的 redux store。注意到这里的装饰器实际除了 app.state.testdata以外还实际接收 app.state.loading 作为参数,这个 loading 的来源是 src/index.js 中调用的 dva-loading 2 这个插件。它返回的信息包含了 global、model 和 effect 的异步加载完成情况。