Lufer

  • 首页
  • 编程
  • 学习笔记
  • 日常折腾
Lufer
Code the World
  1. 首页
  2. 编程
  3. 前端
  4. 正文

AntDesign Pro 快速上手

2019年4月22日 670点热度 0人点赞 0条评论

前期准备

环境配置

  1. 安装Node.js
  2. Clone项目
  3. 本地NPM INSTALL完成相关组件的自动安装

新建页面

项目组织结构:

.
├── /src/            # 项目源码目录
| |—— /assets        # 图标
| |—— /common
|   |—— /menu        # 菜单
    |—— /router      # 路由
| |—— /layouts       # 布局
│ ├── /components/   # 项目组件
│ ├── /routes/       # 路由组件(页面维度)
│ ├── /models/       # 数据模型
│ ├── /services/     # 数据接口
│ ├── /utils/        # 工具函数
│ ├── router.js      # 路由权限?
| |—— config.js      # 全局配置
│ ├── index.js       # 入口文件
│ ├── index.less     
│ └── index.ejs

创建文件

与routes文件夹下按照喜好的组织结构建立js文件。

本例中建立文件夹Tutorial,并建立demo1.js与demo2.js两个页面。

.
├── /src/            
│ ├── /routes/       
    |—— /Tutorial    
        |—— /demo1.js
        |—— /demo2.js

设定菜单

在common/menu下,托管了项目所有的左边栏菜单。

菜单以Json数组形式存在,如下是一个完整的菜单项。

{
    name: 'dashboard',          #菜单名
    icon: 'dashboard',          #菜单图标
    path: 'dashboard',          #菜单路径
    authority: 'admin',         #权限控制    
    children: [                 #子菜单
      {                            
        name: '分析页',         
        path: 'analysis',
      },
    ],
},

我们在其中添加一个菜单项。

{
    name: 'AntD-Tutorial',      
    icon: 'dashboard',         
    path: 'tutorial',   
    children: [                
      {                            
        name: '演示页面1',         
        path: 'demo1',
      },
      {                            
        name: '演示页面2',         
        path: 'demo2',
      },
    ],       
},

关联菜单与页面

在菜单页中,我们将两个子菜单分别指向了:
/tutorial/demo1
/tutorial/demo2

接下来需要接管该路径,指向对应的js文件。

修改/common/router.js。

在routerConfig项中添加如下所示路径,即可绑定地址与页面。

'/tutorial/demo1': {
    component: dynamicWrapper(app, [], () => import('../routes/Tutorial/demo1')),
},
'/tutorial/demo2': {
    component: dynamicWrapper(app, [], () => import('../routes/Tutorial/demo2')),
},

页面1-原生开发

在demo1,我们将介绍AntDesign架构的原生开发方式,也借此来理解AntDesign的页面生命周期与数据驱动流程。

我们建立一个十分简单的空白页面demo1,并逐步丰富内容来实现最终功能

import React, { Component, Fragment } from 'react';

export default class demo1 extends Component {
  componentDidMount() {
  }

  render() {
    return (
      <Fragment>

      </Fragment>
    );
  }
}

AntDesign提供了十分丰富的标准页面,例如表单页,列表页,详情页等,我们这里手动实现一次列表页。

既然是数据驱动,所以我们从数据开始,像页面倒推实现过程。

向后端发起请求

所有向后端发起的请求,均托管于servvices/api.js中。

我们在其中实现一个请求函数。

这里强调一下,既然是前后端分离开发,所以各部分人员可以各司其职,并不需要相互制约,只要制定了前后端的数据格式,并且双方均遵守,即可各自分离开发,在最后阶段进行联调即可。

为了实现分离开发,前端可以在自行开发阶段对请求自动进行返回。

此时我们实现如下所示的一个请求函数:

export async function GetDataFromBackStage() {
  return request('/api/fake_get_data');
}

此处可见,我们向api/fake_get_data发起了一个请求。

前端提供了一个mock工具,RoadHog,用于拦截请求,返回数据,从而让前端开发不再依赖于后端。

我们在.roadhogrc.mock.js中对该请求进行一个拦截并模拟了一组返回值。

其语法是请求方式 请求路径:{返回值}。

'GET /api/fake_get_data': {
    "pagination":
      { "total": 1, "current": 1, "pageSize": 10 },
    "list": [
      {
        "dataid": 1,
        "time": "2018-10-25T12:29:25.000+0000",
        "datasourcetype": "kafka",
        "status": 1,
        "name": "测试用-北京出租车GPS数据",
        "datatype": 0,
        "crossprovince": 1,
        "datalocation": "北京市",
        "datafield": 1,
        "company": "Didicompany",
        "datadescription": "测试用-北京出租车GPS数据",
        "ownnode": 5,
        "datadefinition": "字段名:StrCompanyID,数据类型:string,字段说明:StrCompanyID;字段名:StrDepLongitude,数据类型:double,字段说明:StrDepLongitude;字段名:StrDepLatitude,数据类型:double,字段说明:StrDepLatitude;字段名:StrOrderID,数据类型:string,字段说明:StrOrderID;",
        "url": "/user/download?file=f6bbfb6e512531cb78a086b94708f398.166ab336727&name=order_true.json",
        "resourceip": "127.0.0.1",
        "kafkatopic": "ORDER",
        "dataurl": "127.0.0.1:8000",
      },
      {
        "dataid": 2,
        "time": "2018-10-25T12:39:55.000+0000",
        "datasourcetype": "kafka",
        "status": 1,
        "name": "北京出租车GPS数据",
        "datatype": 1,
        "crossprovince": 1,
        "datalocation": "北京市",
        "datafield": 1,
        "company": "Didicompany",
        "datadescription": "北京出租车GPS数据",
        "ownnode": 6,
        "datadefinition": "字段名:StrCompanyID;字段名:StrDepLongitude;字段名:StrDepLatitude;字段名:StrOrderID;",
        "url": "/user/download?file=f6bbfb6e512531cb78a086b94708f398.166ab3d0424&name=order_true.json",
        "resourceip": "192.168.3.19",
        "kafkatopic": "ORDER",
        "dataurl": "192.168.3.19:8000",
      },
    ],
  },

这样在api中发送请求时,roadhog就可以先将请求拦截下,从而方便前端开发,而在进行联调时,仅需更改api中的请求函数,即可与后端进行测试,例如可改成如下代码段。

export async function DataSearch(params) {
  const curToken = token.get();
  return request(`

#123;config.domain}/data/Search`, {
method: 'POST',
headers: {
Authorization: curToken,
},
body: params,
});
}

调用请求发起函数

现在我们有了前后端交互的最后一步,即发起请求的函数,那么我们再向前一步,实现调用该函数的函数。

model层托管了所有的数据服务,我们在Model下新建一个tutorialModel.js,来实现View层与API层的连接。

先放上全部代码,再进行解释。

import { GetDataFromBackStage } from '../services/api';    #从api中引入我们定义的请求函数

export default {
  namespace: 'tutorialModel',      #组件名
  state: {                         #state定义了你的数据格式,我们这里使用了一个data变量
    data: {
      list: [],
      pagination: {},
    },
  },

  effects: {
    *getData({  }, { call, put }) {                         #定义一个getData函数
      const response = yield call(GetDataFromBackStage, );  #调用我们定义的请求发起函数 
      yield put({                                           #这里处理返回值,调用reducer中的saveData,把返回值传过去
        type: 'saveData',
        payload: response,
      });
    },
  },
  reducers: {
    saveData(state, { payload }) {
      return {
        ...state,                                           #将state中的data取出来,并赋新值
        data: payload,
      };
    },
  },
};

至此就完成了数据的获取与保存,在下一步则是进行页面View层的更新。

更新页面

在最后一步,我们完成请求的发起与结果的获取,回到我们的demo.js。

我们以按照DashBoard下面的该表格为例,实现一个表格页面。

调用该组件,我们仅需在render中添加一个table标签,然后绑定各项数据源即可,查看示例页的实现,可见其table参数如下:

<Table
  rowKey={record => record.index}
  size="small"
  columns={columns}
  dataSource={searchData}
  pagination={{
    style: { marginBottom: 0 },
      pageSize: 5,
    }}
/>

我们所要修改的也就是其columns和DataSource了。

首先,在componentDidMount中,通过dispatch方法,发起请求,来触发前几步中所实现的逐项函数,这里才是这些函数的调用起点。

componentDidMount() {
  const { dispatch } = this.props;
  dispatch({
    type: 'tutorialModel/getData',
  });
}

通过connect,将model和这个页面的component连接起来,从而可以在页面中调用model保存下来的数值。

@connect(({ tutorialModel}) => ({
  tutorialModel,
}))

注意,@connect要写在component定义的前面。

获取到的数据是保存在props中的,我们先把数据解构出来,方面后面调用。

const { tutorialModel }=this.props;
const { data }=tutorialModel;

再定义一下表格的各列信息。

const columns = [
      {
        title: '数据名称',
        dataIndex: 'name',
      },
      {
        title: '描述',
        dataIndex: 'datadescription',
      },
      {
        title: '数据领域',
        dataIndex: 'datafield',
      },
      {
        title: '状态',
        dataIndex: 'status',
      },
      {
        title: '时间',
        dataIndex: 'time',
      },
    ];

最后在配置一下Table的各项数据源。

<Table
          rowKey="dataid"
          size="small"
          columns={columns}
          dataSource={data.list}
          pagination={{
              style: { marginBottom: 0 },
              pageSize: 5,
            }}
        />

完成,运行效果如图:

页面完整代码如下。

import React, { Component } from 'react';
import { connect } from 'dva';
import { Card,Table} from 'antd';

@connect(({ tutorialModel }) => ({
  tutorialModel,
}))

export default class demo1 extends Component {

  componentDidMount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'tutorialModel/getData',
    });
  }

  render() {
    const { tutorialModel }=this.props;
    const { data }=tutorialModel;
    const columns = [
      {
        title: '数据名称',
        dataIndex: 'name',
      },
      {
        title: '描述',
        dataIndex: 'datadescription',
      },
      {
        title: '数据领域',
        dataIndex: 'datafield',
      },
      {
        title: '状态',
        dataIndex: 'status',
      },
      {
        title: '时间',
        dataIndex: 'time',
      },
    ];

    return (
      <Card bordered={false}>
        <Table
          rowKey="dataid"
          size="small"
          columns={columns}
          dataSource={data.list}
          pagination={{
              style: { marginBottom: 0 },
              pageSize: 5,
            }}
        />
      </Card>
    );
  }
}

最后注意,要修改一下router,将我们定义的model传给页面,否则会找不到数据。

'/tutorial/demo1': {
  component: dynamicWrapper(app, ['tutorialModel'], () => import('../routes/Tutorial/demo1')),
},

页面2-快速移植

在页面2,我们将演示如何快速的将一个现有页面完成移植。

我们要实现的目标页面如下图所示:

静态文件移植

相关json文件,js文件,css文件等静态文件,全部放在public目录下

静态文件引入

JS文件,在index.ejs中进行引入。

CSS文件,在同级目录下,建立demo2.less文件。

将页面中自定义的css样式复制其中,注意这里的css命名不能带“-”。

通过@import的方式,引入现成的静态CSS文件,代码如下:

@import '/css/commons.min.css';
@import '/css/scheme-polygon.min.css';
@import '//minedata.cn/minemapapi/v1.4/minemap.css';


.buttongroup {
  position: absolute;
  top: 20px;
  right: 120px;
  z-index: 3;
}

.mybutton {
  background-color: #257962;
  border: none;
  color: white;
  padding: 10px 25px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  margin: 10px;
  cursor: pointer;
}

.leftlist{
  background-color: #333333;
  position: absolute;
  left:15%;
  top:10%;
  opacity: .6;
  color:#ffffff;
  border-radius: 5px;
}

.table-row:hover {
  background-color: #666666;
}
#map-legend-box{
  display:none !important
}

页面实现

将原页面的HTML代码,全部放在render的return中,这里注意,所有的style需要改为json数组的形式进行实现,不能写成HTML的形式,而通过className方式引入的css样式可以正常使用。

代码节选如下:

render() {
   return (
     <div>
       <div id="map"  style={{width: '100%',height:'700px'}}>
         <div className="map-control-box" id="map-control-box">
           <div id="map-control-btn-box" className="map-control-btn-box-dgmsd">
           </div>
           <div id="tipBox" className="tip-box-dgmsd select-1">
             <div id="tipInfo" className="tip-info"></div>
           </div>
         </div>
         <div id="map-legend-box" className="map-legend-box" style={{display:"none"}}>
         </div>
         <div className="map-select-locale" id="map-select-locale">
           <div className="select-control-1 btn-select-locale" id="select-control-1">
             <div className="select-text">2D</div>
           </div>
           <div className="select-control-2" id="select-control-2">
             <div className="select-text">3D</div>
           </div>
         </div>
     </div>
     .........
     </div>
   );
 }

完成页面移植,效果如下图:

当然,这其中还需要做一些元素位置,部分js代码的微调。

JS代码

如果页面有JS代码需要实现,只需写在componentDidMount中即可,以D3拓扑图为例。

代码节选如下:

componentDidMount() {

   var width = document.getElementById("knowledge_graph").offsetWidth;
   var height = document.getElementById("knowledge_graph").offsetHeight;
   var img_w = 32;
   var img_h = 32;

   var svg = d3.select("#knowledge_graph").append("svg")
     .attr("width",width)
     .attr("height",height)
     .attr("vertical-align","center");

   d3.json("http://47.92.162.213:8080/static/data/topology.json",function(error,root){

     if( error ){
       return console.log(error);
     }
     console.log(root);

     var force = d3.layout.force()
       .nodes(root.nodes)
       .links(root.edges)
       .size([width,height])
       .linkDistance(90)
       .charge(-500)
       .start();

     ...........

其运行结果如下图,图标资源没有修改路径,所以没有加载,但功能均正常。

此页面在Dashboard/helloworld下可以看见源码。

最后-数据调用

如果你需要用该框架获取数据,在用自己的JS逻辑来实现页面。

在数据获取阶段,需要参考第一部分的原生开发方式,在model,api,和页面中完成数据获取阶段,随后数据就被保存在了props中。

接下来如果想实现自己的逻辑,我在这里以echarts为例,部分代码如下:

componentDidMount() {
  //获取你的数据
  ........
  //开始实现echarts
  // echarts原来该怎么写就怎么写
  var myChart = echarts.init(document.getElementById('main'));
  myChart.setOption({
      title: { text: '某地区蒸发量和降水量' },
      tooltip : {
        trigger: 'axis'
    },
    legend: {
        data:['蒸发量','降水量']
    },
    toolbox: {
        show : true,
        feature : {
            dataView : {show: true, readOnly: false},
            magicType : {show: true, type: ['line', 'bar']},
            restore : {show: true},
            saveAsImage : {
              show: true,
              type: 'jpg'
            }
        }
    },
      xAxis : [
        {
            type : 'category',
            data : this.props.data.xdata    //在这里使用你的数据即可
        }
    ],
    yAxis : [
        {
            type : 'value'
        }
    ],
      series : [
        {
            name:'蒸发量',
            type:'bar',
            data: this.props.data.ydata.ydata1,
            markPoint : {
                data : [
                    {type : 'max', name: '最大值'},
                    {type : 'min', name: '最小值'}
                ]
            },
.........................
标签: AntDesign React
最后更新:2023年7月10日

Lufer

新的一天开始啦

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

文章目录
  • 前期准备
    • 环境配置
  • 新建页面
    • 创建文件
    • 设定菜单
    • 关联菜单与页面
  • 页面1-原生开发
    • 向后端发起请求
    • 调用请求发起函数
    • 更新页面
  • 页面2-快速移植
    • 静态文件移植
    • 静态文件引入
    • 页面实现
    • JS代码
  • 最后-数据调用

COPYRIGHT © 2022 lufer.cc.

Theme Kratos Made By Seaton Jiang

鲁ICP备2021045819号