一、Ant Design Pro新增单个页面目录
1、 client -> src -> pages 中新增文件夹,比如 category的list
├── category
└── list
└── _mock.js // 模拟数据(可忽略)
└── model.js // 处理请求的model组件,如果简单请求,直接写到 index.jsx中,简单化。(可忽略)
└── index.jsx // 主要的核心文件
└── service.js // 接口请求合集
└── style.less // category 公共样式
2、在 client -> config -> conifig.js 中 配置的routes 或者 route.js 中添加路由
{ path: '/category', name: '分类', icon: 'category', routes: [ { path: '/category/list', name: '分类列表列表', component: './category/list' } ] },
index.jsx
import React, { Component } from 'react'; import { PageContainer } from '@ant-design/pro-layout'; // 引入布局组件 import { Card, Table, Select, Form, DatePicker, Button, Pagination } from 'antd'; // 引入ant design ui组件 import { getCategoryList } from '../service'; // 引入请求接口 import moment from 'moment'; // 时间日期组件,时间格式 import styles from '../style.less'; // 引入公共样式,styles.class const { Option } = Select; // 下拉框引入 Option const { RangePicker } = DatePicker; // 时间日期组件引入 RangePicker const dateFormat = 'YYYY-MM-DD'; // 时间日期格式 // 筛选项变量 const selectData = [ { label: '所属渠道', name: 'channel', style: { '100px' }, options: [ { value: 'website', name: '站内', }, { value: 'email', name: '邮件', } ] }, ]; // 创建类组件实例 class categoryList extends Component { // 获取 DOM 元素节点,通过设置 ref,这里是表单form的ref formRef = React.createRef(); constructor(props) { super(props); this.state = { channel: '', selectSourceData: [], categoryListSource: [], } } // 数据初始化 componentDidMount() { // 获取categoryList数据,注意最好不要和service中函数名重复 this.getCategoryListFn(); // 设置筛选项 this.setState({ selectSourceData: selectData }) }; // 获取 categoryList getCategoryListFn = ( params ) => { params = params ? params : { chanel: 'website' }; // 设置一个默认值,可随意自定义 getCategoryList({ ...params }).then(res => { // 可以定义分页参数 if (res.status == 200 ) { const { data } = res; this.setState({ categoryListSource: data.list }) } }); } // 切换筛选项 selectChange = (value, attr) => { // 双向绑定 this.setState({ [attr.key]: value }); // 自定义其他操作 } // 重置 onReset = () => { this.formRef.current.resetFields(); // 重置初始化 this.setState({ selectSourceData: selectData }) }; // 搜索提交,请求list,更新table onFinish = (values) => { this.getStatDataFn({ channel: values.channel || '', }) } // render render() { const columns = [ { title: '推送时间', dataIndex: 'push_time', key: 'push_time', align: 'center', 150, }, { title: '事件名称', dataIndex: 'event_name', key: 'event_name', align: 'center', 150, }, ]; const { loading } = this.props; const { dateRange, selectSourceData, categoryListSource} = this.state; return ( <PageContainer> <Card className={styles.tabsCard} > <Form layout="inline" ref={this.formRef} name="searchObj" className={styles.formBox} initialValues={{ channel: '', dateRange: [], }} onFinish={this.onFinish} onReset={this.onReset} > {selectSourceData.map(item => ( <Form.Item name={item.name} label={item.label} key={item.name} className={styles.formItem} > <Select value={item.name} style={item.style} placeholder="请选择" disabled={item.disabled} onChange={this.selectChange} > {item.options.map((val, index) => ( <Option key={index} disabled={val.disabled} type={item.name} value={val.value}>{val.name}</Option> ))} </Select> </Form.Item> ))} <Form.Item key='dateRange' name="dateRange" className={styles.formItem} > <RangePicker value={dateRange.length ? [moment(dateRange[0], dateFormat), moment(dateRange[1], dateFormat)] : null} // 重置设置 type="dateRange" placeholder={['开始时间', '结束时间']} format={dateFormat} onChange={(value, dateString) => { this.setState({ dateRange: dateString }) }} /> </Form.Item> <Form.Item> <Button type="primary" htmlType="submit">搜索</Button> </Form.Item> <Form.Item> <Button type="default" htmlType="reset">重置</Button> </Form.Item> </Form> <Table dataSource={categoryListSource} bordered={true} scroll={{ x: 2400 }} // 超出滚动,最大宽度 columns={columns} rowKey={(record, index) => index} // pagination={pagination} // pagination={false} loading={loading} // onChange={this.handleTableChange} /> </Card> </PageContainer> ) } }
service.js
// 封装axios,拦截器interceptors import request from '@/utils/request'; // 获取分类列表 export async function getCategoryList(params) { return request('/admin/report/get-category-list', { method: 'POST', data: params, }); }
二、编译可能出现警告:
There are multiple modules with names that only differ in casing. This can lead to unexpected behavior when compiling on a filesystem with other case-semantic. Use equal casing. Compare these module identifiers
1、新增文件夹名注意都要小写,如果多个单词,用横杠 — 隔开
2、import 引入的文件注意文件名的大小写: impor request form '../utils/request.js'
Each child in a list should have a unique "key" prop,Check this render methods of 'Body'
1、如果是table组件,官方给 Table 组件提供了一个 rowKey
属性,用于给表格的每一行设定一个 key 值
<Table dataSource={this.state.tableDataSource} rowKey={(record, index) => index} // 或者 record.id,index好像启用了,最好用唯一字段或者拼接字段 > </Table>
2、如果是 map() 循环,遍历的时候也必须给 key 值
{list.map((item, index) => { <p key={index}>{{item}}</p> }) }
Missing message: "menu.分类管理.分类列表" for locale: "zh-CN", using default message as fallback
这是菜单翻译缺少,请求的菜单需要同步更新
找到 client -> src -> locales -> zh-CN -> menu.js
'menu.分类管理.分类列表': '分类列表',
三、本地开发 menu 导航栏无法加载问题 (https://github.com/ant-design/ant-design-pro/issues/7530)
1、找到 client -> defaultSettings.js, 里面 menus 先注释掉
2、找到 client -> src -> layouts -> Basiclayout.jsx,找到里面 ProLayout 标签,在 menuDataRender 属性配置上面加上配置 menu={{ loading }}
四、componentDidmount 获取父组件 this.props 中异步数据的失效
这个时候,可以使用更新过程中生命周期 componentWillReceiveProps(nextProps) 来获取异步ajax请求的数据 nextProps
1、在接受父组件改变后的 props 需要重新渲染组件时用到的比较多
2、接受一个参数 nextProps
3、通过对比 nextProps 和 this.props,将 nextProps 的state为当前组件的state,从而重新渲染组件
五、ant design 关于 Datepicker 限制时间范围和默认时间
1、限制时间范围
// 使用disbledDate,当前时间到前7天内选择时间, 关于moment.js参考官网 http://momentjs.cn/ const disabledDate = (current) => { // moment().subtract(7, "days") 表示当前日期往前推移7天 // moment().endOf( "day") 表示当前日期最后的时间23:59:59 return current && (current < moment().subtract(7, "days") || current >= moment().endOf('day') } <RangPicker disabledDate={this.disabledDate}>
2、默认时间
const dateFormat = 'YYYY-MM-DD'; this.state = { // 当前时间到前30天内 dateRange: [moment().subtract(30, 'days'), moment()], } <RangePicker value={dateRange.length ? [moment(dateRange[0], dateFormat), moment(dateRange[1], dateFormat)] : null} type="dateRange" format={dateFormat} disabledDate={this.disabledDate} > </RangePicker>