ant-design 简单学习,记录一下。

ant design4.0官网

语雀教程:附带github源码

umi脚手架官网教程

ant-design-pro官网v4 附带开发手册 效果预览

umi脚手架

因为umi是阿里工具,所以使用tyarn安装。

  1. # 安装
  2. $ yarn global add umi
  3. # 更新umi
  4. yarn global upgrade umi

项目初始化

  1. # 新建应用
  2. yarn create umi project_name
  3. 选择 antd 、 dva 、js、npm

新建页面

  1. export default () => {
  2. return <div>hello world</div>;
  3. }

外部可以引用

  1. import React from 'react';
  2. class ShoppingList extends React.Component {
  3. constructor(props) {
  4. super(props);
  5. this.state = {
  6. value: null,
  7. };
  8. }
  9. componentDidMount() {
  10. }
  11. componentWillUnmount() {
  12. }
  13. componentDidUpdate() {
  14. }
  15. render() {
  16. const picture = {
  17. src: 'https://cdn.nlark.com/yuque/0/2018/jpeg/84141/1536207007004-59352a41-4ad8-409b-a416-a4f324eb6d0b.jpeg',
  18. };
  19. return (
  20. <div className="shopping-list">
  21. <h1>Shopping List for {this.props.name}</h1>
  22. <ul>
  23. <li>Instagram</li>
  24. <li>WhatsApp</li>
  25. <li>Oculus</li>
  26. </ul>
  27. </div>
  28. );
  29. }
  30. }
  31. export default ShoppingList;

路由

  1. routes: [
  2. {
  3. path: '/user',
  4. component: '../layouts/UserLayout',
  5. routes: [
  6. {
  7. name: 'login',
  8. path: '/user/login',
  9. component: './user/login',
  10. },
  11. {
  12. name: 'UserDashboard',
  13. icon: 'smile',
  14. path: '/user-dashboard',
  15. component: './user-dashboard',
  16. },
  17. ],
  18. },
  19. {
  20. path: '/',
  21. component: '../layouts/SecurityLayout',
  22. routes: [
  23. {
  24. path: '/',
  25. component: '../layouts/BasicLayout',
  26. authority: ['admin', 'user'],
  27. routes: [
  28. {
  29. path: '/',
  30. redirect: '/welcome',
  31. },
  32. {
  33. path: '/welcome',
  34. name: 'welcome',
  35. icon: 'smile',
  36. component: './Welcome',
  37. },
  38. {
  39. name: '监控页',
  40. icon: 'smile',
  41. path: '/dashboardmonitor1',
  42. component: './DashboardMonitor',
  43. },
  44. {
  45. component: './404',
  46. },
  47. ],
  48. },
  49. {
  50. component: './404',
  51. },
  52. ],
  53. },
  54. {
  55. component: './404',
  56. },
  57. ],

布局

布局

  1. import { Layout } from 'antd';
  2. const { Header, Footer, Sider, Content } = Layout;
  3. ReactDOM.render(
  4. <div>
  5. <Layout>
  6. <Header>Header</Header>
  7. <Content>Content</Content>
  8. <Footer>Footer</Footer>
  9. </Layout>
  10. <Layout>
  11. <Sider>Sider</Sider>
  12. <Layout>
  13. <Header>Header</Header>
  14. <Content>Content</Content>
  15. <Footer>Footer</Footer>
  16. </Layout>
  17. </Layout>
  18. </div>,
  19. mountNode,
  20. );

栅格

栅格

  1. import { Row, Col } from 'antd';
  2. ReactDOM.render(
  3. <div>
  4. <Row>
  5. <Col span={12}>col-12</Col>
  6. <Col span={12}>col-12</Col>
  7. </Row>
  8. <Row>
  9. <Col span={8}>col-8</Col>
  10. <Col span={8}>col-8</Col>
  11. <Col span={8}>col-8</Col>
  12. </Row>
  13. </div>,
  14. mountNode,
  15. );

示例

效果:

测试.gif

结构:

image.png

index.jsx

页面元素

  1. import React from 'react';
  2. import { connect } from 'dva';
  3. import { Table, Modal, Button, Form, Input } from 'antd';
  4. import SampleChart from '../../components/SampleChart';
  5. const FormItem = Form.Item;
  6. class List extends React.Component {
  7. state = {
  8. visible: false,
  9. statisticVisible: false,
  10. id: null,
  11. };
  12. columns = [
  13. {
  14. title: '名称',
  15. dataIndex: 'name',
  16. },
  17. {
  18. title: '描述',
  19. dataIndex: 'desc',
  20. },
  21. {
  22. title: '链接',
  23. dataIndex: 'url',
  24. render: value => <a href={value}>{value}</a>,
  25. },
  26. {
  27. title: '',
  28. dataIndex: 'statistic',
  29. render: (_, { id }) => {
  30. return (
  31. <Button onClick={() => { this.showStatistic(id); }}>图表</Button>
  32. );
  33. },
  34. },
  35. ];
  36. showModel = () => {
  37. this.setState({ visible: true })
  38. };
  39. handleCancel = () => {
  40. this.setState({
  41. visible: false,
  42. });
  43. };
  44. handleStatisticCancel = () => {
  45. this.setState({
  46. statisticVisible: false,
  47. });
  48. };
  49. showStatistic = (id) => {
  50. this.props.dispatch({
  51. type: 'cards/getStatistic',
  52. payload: id,
  53. });
  54. this.setState({ id, statisticVisible: true });
  55. };
  56. handleOk = () => {
  57. const { dispatch, form: { validateFields } } = this.props;
  58. validateFields((err, values) => {
  59. if (!err) {
  60. dispatch({
  61. type: 'cards/addOne',
  62. payload: values,
  63. });
  64. // 重置 `visible` 属性为 false 以关闭对话框
  65. this.setState({ visible: false });
  66. }
  67. });
  68. };
  69. componentDidMount() {
  70. this.props.dispatch({
  71. type: 'cards/queryList',
  72. });
  73. }
  74. render() {
  75. const { visible, statisticVisible, id } = this.state;
  76. const { cardsList, cardsLoading, form: { getFieldDecorator }, statistic } = this.props;
  77. return (
  78. <div>
  79. <Table columns={this.columns} dataSource={cardsList} loading={cardsLoading} rowKey="id"/>
  80. <Button onClick={this.showModel}>新建</Button>
  81. <Modal title="新建记录"
  82. visible={visible}
  83. onOk={this.handleOk}
  84. onCancel={this.handleCancel}
  85. >
  86. <Form>
  87. <FormItem label="名称">
  88. {getFieldDecorator('name', {
  89. rules: [{ required: true }],
  90. })(
  91. <Input/>
  92. )}
  93. </FormItem>
  94. <FormItem label="描述">
  95. {getFieldDecorator('desc')(
  96. <Input/>
  97. )}
  98. </FormItem>
  99. <FormItem label="链接">
  100. {getFieldDecorator('url', {
  101. rules: [{ type: 'url' }],
  102. })(
  103. <Input/>
  104. )}
  105. </FormItem>
  106. </Form>
  107. </Modal>
  108. <Modal visible={statisticVisible} footer={null} onCancel={this.handleStatisticCancel}>
  109. <SampleChart data={statistic[id]} />
  110. </Modal>
  111. </div>
  112. );
  113. }
  114. }
  115. function mapStateToProps(state) {
  116. return {
  117. cardsList: state.cards.cardsList,
  118. cardsLoading: state.loading.effects['cards/queryList'],
  119. statistic: state.cards.statistic,
  120. };
  121. }
  122. export default connect(mapStateToProps)(Form.create()(List));

model.js

页面所有方法

  1. import * as service from './service';
  2. export default {
  3. namespace: 'cards',
  4. state: {
  5. cardsList: [],
  6. statistic: {},
  7. },
  8. effects: {
  9. * queryList({ payload }, { call, put }) {
  10. const rsp = yield call(service.queryList, payload);
  11. yield put({
  12. type: 'initList',
  13. payload: { cardsList: rsp.result }
  14. });
  15. },
  16. *deleteOne({ payload }, { call, put }) {
  17. const rsp = yield call(service.deleteOne, payload);
  18. return rsp;
  19. },
  20. *addOne({ payload }, { call, put }) {
  21. const rsp = yield call(service.addOne, payload);
  22. yield put({ type: 'queryList' });
  23. return rsp;
  24. },
  25. *getStatistic({ payload }, { call, put }) {
  26. const rsp = yield call(service.getStatistic, payload);
  27. yield put({
  28. type: 'saveStatistic',
  29. payload: {
  30. id: payload,
  31. data: rsp.result,
  32. },
  33. });
  34. return rsp;
  35. },
  36. },
  37. reducers: {
  38. initList(state, { payload: { cardsList } }) {
  39. return {
  40. ...state,
  41. cardsList
  42. };
  43. },
  44. saveStatistic(state, { payload: { id, data } }) {
  45. return {
  46. ...state,
  47. statistic: {
  48. ...state.statistic,
  49. [id]: data,
  50. },
  51. }
  52. },
  53. }
  54. };

service.js

所有异步请求

  1. import request from '@/utils/request';
  2. export function queryList() {
  3. return request('/api/cards');
  4. }
  5. export function deleteOne(id) {
  6. return request(`/api/cards/${id}`, {
  7. method: 'DELETE'
  8. });
  9. }
  10. export function addOne(data) {
  11. return request('/api/cards/add', {
  12. headers: {
  13. 'content-type': 'application/json',
  14. },
  15. method: 'POST',
  16. body: JSON.stringify(data),
  17. });
  18. }
  19. export function getStatistic(id) {
  20. return request(`/api/cards/${id}/statistic`);
  21. }

_mock.js

模拟数据

  1. let data = [
  2. {
  3. id: 1,
  4. name: 'umi',
  5. desc: '极快的类 Next.js 的 React 应用框架。',
  6. url: 'https://umijs.org'
  7. },
  8. {
  9. id: 2,
  10. name: 'antd',
  11. desc: '一个服务于企业级产品的设计体系。',
  12. url: 'https://ant.design/index-cn'
  13. },
  14. {
  15. id: 3,
  16. name: 'antd-pro',
  17. desc: '一个服务于企业级产品的设计体系。',
  18. url: 'https://ant.design/index-cn'
  19. }
  20. ];
  21. export default {
  22. 'get /api/cards': function (req, res, next) {
  23. setTimeout(() => {
  24. res.json({
  25. result: data,
  26. })
  27. }, 250)
  28. },
  29. 'delete /api/cards/:id': function (req, res, next) {
  30. data = data.filter(v => v.id !== parseInt(req.params.id));
  31. console.log(req.params.id);
  32. console.log(data);
  33. setTimeout(() => {
  34. res.json({
  35. success: true,
  36. })
  37. }, 250)
  38. },
  39. 'post /api/cards/add': function (req, res, next) {
  40. data = [...data, {
  41. ...req.body,
  42. id: data[data.length - 1].id + 1,
  43. }];
  44. res.json({
  45. success: true,
  46. });
  47. },
  48. 'get /api/cards/:id/statistic': function (req, res, next) {
  49. res.json({
  50. result: [
  51. { genre: 'Sports', sold: 275 },
  52. { genre: 'Strategy', sold: 1150 },
  53. { genre: 'Action', sold: 120 },
  54. { genre: 'Shooter', sold: 350 },
  55. { genre: 'Other', sold: 150 },
  56. ]
  57. });
  58. },
  59. }

附带一个 SampleChart

  1. import React from 'react';
  2. import G2 from '@antv/g2';
  3. class SampleChart extends React.Component {
  4. constructor(props) {
  5. super(props);
  6. this.containerRef = React.createRef();
  7. }
  8. componentDidMount() {
  9. this.chart = new G2.Chart({
  10. container: this.containerRef.current,
  11. width: 450,
  12. height: 300
  13. });
  14. this.refreshChart();
  15. }
  16. componentDidUpdate(prevProps) {
  17. if (prevProps.data !== this.props.data) {
  18. this.refreshChart();
  19. }
  20. }
  21. componentWillUnmount() {
  22. if (this.chart) {
  23. this.chart.destroy();
  24. }
  25. }
  26. refreshChart = () => {
  27. this.chart.source(this.props.data);
  28. this.chart.interval().position('genre*sold').color('genre');
  29. this.chart.render();
  30. };
  31. render() {
  32. return (
  33. <div ref={this.containerRef} />
  34. );
  35. }
  36. }
  37. export default SampleChart;

表单操作

数据绑定:

  1. const [noteForm] = Form.useForm();
  2. <Form
  3. {...layout}
  4. name="basic"
  5. initialValues={{}}
  6. onFinish={updatePushUrl}
  7. form={noteForm}
  8. // onFinishFailed={onFinishFailed}
  9. >
  10. <Form.Item
  11. label="提醒地址"
  12. name="noteUrl"
  13. >
  14. <Input/>
  15. </Form.Item>
  16. <Form.Item {...tailLayout}>
  17. <Button type="primary" htmlType="submit">
  18. 提交
  19. </Button>
  20. </Form.Item>
  21. </Form>

赋值

  1. noteForm.setFieldsValue({"noteUrl": res.data});

提交

  1. const updatePushUrl = (values: PushChange) => {
  2. service.updatePushUrl(values);
  3. }