脚手架下载
软件环境:NodeJS,Git
下载步骤:
1、clone代码。其中ant_design 为文件夹名
$ git clone --depth=1 https://github.com/ant-design/ant-design-pro.git ant_design
$ cd ant_design
2、下载依赖
npm install
PS: 下载依赖时设置国内镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
npm config set registry https://registry.npm.taobao.org
3、运行
npm start
浏览器输入地址 http://localhost:8000,登登登,首页出来了。
Ant Design Pro 浅析
菜单映射
菜单配置主要在文件【config/route.config.js]】,代码如下:
export default [
{
path: '/',
component: '../layouts/BasicLayout',
Routes: ['src/pages/Authorized'],
routes: [
{ path: '/', redirect: '/dashboard/analysis' },
{
path: '/dashboard',
name: 'dashboard',
icon: 'dashboard',
hideInMenu: false,
hideChildrenInMenu: false,
hideInBreadcrumb: true,
routes: [
{
path: '/dashboard/analysis',
name: 'analysis',
component: './Dashboard/Analysis',
},
{
path: '/dashboard/monitor',
name: 'monitor',
component: './Dashboard/Monitor',
},
{
path: '/dashboard/workplace',
name: 'workplace',
component: './Dashboard/Workplace',
},
],
}
]
}
];
主要看routes列表的元素,这里采用的是约定式路由(UMI).
其中path就是 页面映射的URL,name 是组件的名字, component 这里的当前目录是 src/pages。
页面渲染
import React, { PureComponent, Fragment } from 'react';
import {
DatePicker, message, version, Button
} from 'antd';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import { formatMessage, FormattedMessage } from 'umi/locale';
import style from './default.less';
class MailConfig extends PureComponent {
render() {
return (
<PageHeaderWrapper
title={<FormattedMessage id="app.forms.message.email" />}
>
<div className="App">
<p>Current antd version: {version}</p>
<p>Please fork this codesandbox to reproduce your issue.</p>
<p>请 fork 这个链接来重现你碰到的问题。</p>
<Button type="primary">Hello</Button>
</div>
</PageHeaderWrapper>
);
}
}
export default MailConfig;
ant-design:所有的页面都保存为JS再进行渲染。
import : 根据实际需要引入相应的组件。
@/components/PageHeaderWrapper: 显示页面标题内容的组件。
'umi/locale‘: 国际化资源配置,配置文件在 src/locales 目录下。
export default MailConfig: 表示将当前页面嵌套在当前主题模版里。
界面定义数据交互
官方讲解:
- UI 组件交互操作;
- 调用 model 的 effect;
- 调用统一管理的 service 请求函数;
- 使用封装的 request.js发送请求;
- 获取服务端返回;
- 然后调用 reducer 改变 state; 更新 model。
讲人话:
1、每个页面都是通过一个叫做model的文件做数据配置;
2、调用通用的请求行数;
3、使用request.js提交请求;
4、获取响应信息,进行渲染。
show u the code:
以查询表格(TableList.js)为例。
componentDidMount() {
const { dispatch } = this.props;
dispatch({
type: 'rule/fetch',
});
}
componentDidMount: 加载数据函数
再看同级目录下models/rule.js
import { queryRule, removeRule, addRule, updateRule } from '@/services/api';
...
effects: {
*fetch({ payload }, { call, put }) {
const response = yield call(queryRule, payload);
yield put({
type: 'save',
payload: response,
});
},
使用了后缀模糊匹配。
yield call(queryRule, payload) :queryRule 表示调用了services/api.js 的queryRule, payload 表示传递的参数。
services/api.js 对应的函数如下:
export async function queryRule(params) {
console.log("rule");
return request(`/api/rule?${stringify(params)}`);
}
demo 中的请求都是通过mock来模拟后端的返回数据。这里的请求对应的mock文件是mock/rule.js
import { parse } from 'url';
// mock tableListDataSource
let tableListDataSource = [];
for (let i = 0; i < 46; i += 1) {
tableListDataSource.push({
key: i,
disabled: i % 6 === 0,
href: 'https://ant.design',
avatar: [
'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
][i % 2],
name: `TradeCode ${i}`,
title: `一个任务名称 ${i}`,
owner: '曲丽丽',
desc: '这是一段描述',
callNo: Math.floor(Math.random() * 1000),
status: Math.floor(Math.random() * 10) % 4,
updatedAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
createdAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
progress: Math.ceil(Math.random() * 100),
});
}
function getRule(req, res, u) {
let url = u;
if (!url || Object.prototype.toString.call(url) !== '[object String]') {
url = req.url; // eslint-disable-line
}
const params = parse(url, true).query;
let dataSource = tableListDataSource;
if (params.sorter) {
const s = params.sorter.split('_');
dataSource = dataSource.sort((prev, next) => {
if (s[1] === 'descend') {
return next[s[0]] - prev[s[0]];
}
return prev[s[0]] - next[s[0]];
});
}
if (params.status) {
const status = params.status.split(',');
let filterDataSource = [];
status.forEach(s => {
filterDataSource = filterDataSource.concat(
dataSource.filter(data => parseInt(data.status, 10) === parseInt(s[0], 10))
);
});
dataSource = filterDataSource;
}
if (params.name) {
dataSource = dataSource.filter(data => data.name.indexOf(params.name) > -1);
}
let pageSize = 10;
if (params.pageSize) {
pageSize = params.pageSize * 1;
}
const result = {
list: dataSource,
pagination: {
total: dataSource.length,
pageSize,
current: parseInt(params.currentPage, 10) || 1,
},
};
return res.json(result);
}
function postRule(req, res, u, b) {
let url = u;
if (!url || Object.prototype.toString.call(url) !== '[object String]') {
url = req.url; // eslint-disable-line
}
const body = (b && b.body) || req.body;
const { method, name, desc, key } = body;
switch (method) {
/* eslint no-case-declarations:0 */
case 'delete':
tableListDataSource = tableListDataSource.filter(item => key.indexOf(item.key) === -1);
break;
case 'post':
const i = Math.ceil(Math.random() * 10000);
tableListDataSource.unshift({
key: i,
href: 'https://ant.design',
avatar: [
'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
][i % 2],
name: `TradeCode ${i}`,
title: `一个任务名称 ${i}`,
owner: '曲丽丽',
desc,
callNo: Math.floor(Math.random() * 1000),
status: Math.floor(Math.random() * 10) % 2,
updatedAt: new Date(),
createdAt: new Date(),
progress: Math.ceil(Math.random() * 100),
});
break;
case 'update':
tableListDataSource = tableListDataSource.map(item => {
if (item.key === key) {
Object.assign(item, { desc, name });
return item;
}
return item;
});
break;
default:
break;
}
return getRule(req, res, u);
}
export default {
'GET /api/rule': getRule,
'POST /api/rule': postRule,
};
数据渲染
在页面定义render函数
render() {
const {
conf_email1: { data },
loading,
} = this.props;
const { selectedRows, modalVisible, updateModalVisible, stepFormValues } = this.state;
return (
<PageHeaderWrapper title="查询表格">
<Card bordered={false}>
<div className={styles.tableList}>
<StandardTable
selectedRows={selectedRows}
loading={loading}
data={data}
columns={this.columns}
onSelectRow={this.handleSelectRows}
// onChange={this.handleStandardTableChange}
/>
</div>
</Card>
</PageHeaderWrapper>
);
至此,数据获取并渲染完毕。
后台数据交互
不适用mock,使用真实的服务器接口设置如下:
1、在config/config.js 开启proxy
proxy: {
'/test': {
target: 'http://localhost:9001',
changeOrigin: true,
pathRewrite: { '^/test': '/config/email' },
},
},
代理规则是将含有/test的请求链接中的以/test开头的内容做替换。
如链接为: http://localhost:8000/test/sendMail
经过代理后变成 http://localhost:9001/config/email/sendMail
PS: 转换过程在内部完成,对外还是显示 http://localhost:8000/test/sendMail 。
2、启动后台项目
3、启动ant-design
npm run start:no-mock
至此,数据加载完成。
顺便补摸鱼的中的坑:
1、返回的JSON串字段名注意别使用前端关键字,测试中用了 data和result 数据均显示不了。