1 可视化图表

1.1 常用数据可视化图标库

  1. echarts
    a. https://echarts.baidu.com/b. 百度开源, 如果要在react项目中使用, 需要下载echarts-for-react
  2. G2
    a. https://antv.aplipay.com/zh-ch/g2/3.x/index.htmlb. 阿里开源
  3. bizcharts
    a. https://bizcharts,net/products/bizCharts
    b. 基于react包装G2的开源库
    c. 需要额外下载 @antv/data-set
  4. d3
    a. https://d3js.org.cn/b. 国外的免费可视化图表库

1.2 下载依赖

npm install echarts echarts-for-react
npm install bizcharts @antv/data-set

1.3 echarts 柱形图

首先分析一下我们想要实现的页面结构,首先是两个区域, 第一个区域是一个更新按钮, 第二个区域是echarts柱形图, 我们使用Card来实现, 柱形图需要有两个系列的数据, 分别为销量和库存. 更新按钮的功能是将销量的数据全都+1, 库存的数据全部-1.

react数据可视化库 react 可视化_react数据可视化库

然后我们知道echarts是通过配置options来实现可视化的,所以我们也需要配置一下来达到我们的需求:

{
    title: {
        text: 'ECharts 入门示例', // 在左上角显示title标题文字
    },
        tooltip: {},
            legend: {
                data: ['销量','库存'] // 所有的数据种类
            },
                xAxis: {
                    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'] // X轴
                },
                    yAxis: {}, // y轴
                        series: [
                            {
                                name: '销量',
                                type: 'bar',
                                data: sales
                            },
                            {
                                name: '库存',
                                type: 'bar',
                                data: stores
                            },
                        ]
}

至此可以写出Bar.js的所有代码:

import React, { Component } from 'react'
import { Card, Button } from "antd"
import ReactECharts from "echarts-for-react"


export default class Bar extends Component {

    state = {
        sales: [5, 20, 36, 10, 10, 20], // 销量数组
        stores: [35, 20, 4, 30, 30, 20], // 库存数组
    }

    update = () => {
        this.setState( state => ({
            sales:state.sales.map(sale => sale + 1),
            stores:state.stores.reduce((pre, store) => {
                if(store === 0) {
                    pre.push(store)
                } else {
                    pre.push(store - 1)
                }
                return pre
            }, []),
        }))
    }

    // 返回柱状图的配置对象
    getOption = (sales, stores) => {
        
        return ({
            title: {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data: ['销量','库存']
            },
            xAxis: {
                data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
            },
            yAxis: {},
            series: [
            {
                name: '销量',
                type: 'bar',
                data: sales
            },
            {
                name: '库存',
                type: 'bar',
                data: stores
            },
            ]
        })
    }

    render() {
        const {sales, stores} = this.state
        return (
            <div>
                <Card>
                    <Button type="primary" onClick={this.update}>更新</Button>
                </Card>
                <Card title="柱状图一">
                    <ReactECharts 
                        option={this.getOption(sales,stores)} // options:图表配置项
                    />
                </Card>
                
            </div>
        )
    }
}

1.2 前台404组件页面

我们现在的需求是当用户输入一个不存在的路由时, 需要弹出404页面并且有返回按钮可以返回首页我们需要写一个新的组件PageNotFound, 简单的写一下代码和样式:

PageNotFound/index.jsx

import React, { Component } from 'react'
import {Button, Row, Col} from "antd"
import "./index.less"

// 前台404页面
export default class PageNotFound extends Component {
    goHome = () => {
        this.props.history.replace("/home")
    }

    render() {
        return (
            <Row className='not-found'>
                <Col span={12} className="left"></Col>
                <Col span={12} className="right">
                    <h1>404</h1>
                    <h2>抱歉,您访问的页面不存在</h2>
                    <div>
                        <Button type="primary" onClick={this.goHome}>
                            回到首页
                        </Button>
                    </div>
                </Col>
            </Row>
        )
    }
}

PageNotFound/index.less

.not-found {
    background-color: #f0f2f5;
    height: 100%;
    .left {
        height: 100%;
        background: url("./images/404.png") no-repeat center;
    }
    .right {
        padding-left: 50px;
        margin-top: 150px;
        h1 {
            font-size: 35px;
        }
        h2 {
            margin-bottom: 20px;
            font-size: 20px;
        }
    }
}

将404.png放置在PageNotFound的images文件夹下, 然后使用严格匹配修改路由的匹配规则:

<Switch>
    <Redirect exact from='/' to="/home"/>
    <Route path="/home" component={Home}/>
    <Route path="/category" component={Category}/>
    <Route path="/product" component={Product}/>
    <Route path="/role" component={Role}/>
    <Route path="/user" component={User}/>
    <Route path="/charts/bar" component={Bar}/>
    <Route path="/charts/line" component={Line}/>
    <Route path="/charts/pie" component={Pie}/>
    <Route component={PageNotFound} />
</Switch>

然后进行测试的时候发现我们在输入错误的路由时headTitle也还是原来的, 所以我们应该在PageNotFound里使用redux来设置headTitle, 将reduer.js中initHeadTitle设置为"":

PageNotFound/index.jsx 最终代码:

import React, { Component } from 'react'
import {Button, Row, Col} from "antd"
import { connect } from "react-redux"
import { setHeadTitle } from '../../redux/actions'

import "./index.less"

// 前台404页面
class PageNotFound extends Component {
    goHome = () => {
        this.props.setHeadTitle("首页")
        this.props.history.replace("/home")
    }

    render() {
        return (
            <Row className='not-found'>
                <Col span={12} className="left"></Col>
                <Col span={12} className="right">
                    <h1>404</h1>
                    <h2>抱歉,您访问的页面不存在</h2>
                    <div>
                        <Button type="primary" onClick={this.goHome}>
                            回到首页
                        </Button>
                    </div>
                </Col>
            </Row>
        )
    }
}

export default connect(
    state => ({}),
    { setHeadTitle }
)(PageNotFound)

react数据可视化库 react 可视化_react数据可视化库_02

2 使用HashRouter 替代BrowserRouter

实际开发环境中我们使用更多的时HashRouter, 我们在App.js使用HashRouter代替BrowserRouter.

App.js

/*
    应用的根组件
 */

import React, { Component } from 'react';
import {HashRouter, Route,Switch} from "react-router-dom";
import Login from './pages/Login';
import Admin from './pages/Admin';


export default class App extends Component {

    render() {
        return (
            <HashRouter>
                <Switch> {/* 只匹配其中一个,而且是从上往下对比 */}
                    <Route path="/login" component={Login}></Route>
                    <Route path="/" component={Admin}></Route>
                </Switch>
            </HashRouter>
        )
    }
}

此时会产生一个问题, 我们在Product组件块上点击详情和更新时要跳转路由, 当时用的是BrowerRouter自带的功能传递过去, 现在不行了, 我们使用utils里的memoryUtils来保存当前product数据, 并在组件将要被卸载时将其中data数据清空就可以完美解决问题.

memoryUtils.js

/* 
    用来在内存中存储一些数据的工具模块
*/

let  memoryUtils = {
    user: {}, //保存当前登录的user
    product: {}, // 指定的商品对象
}

export default memoryUtils;

3 nginx 解决跨域

在项目打包之后, 当前端请求后端数据库而不在同一个端口号时, 就会产生跨域问题, 跨域问题可以后端通过cors解决, 也可以通过前端配置nginx解决:

3.1 nginx常用命令

start nginx 开启nginx
nginx -s reload #重新加载Nginx配置文件,然后以优雅的方式重启Nginx
nginx -s stop #强制停止Nginx服务
nginx -s quit #优雅地停止Nginx服务(即处理完所有请求后再停止服务)

3.2 配置conf

nginx.conf中http server的配置

server {
        # nginx 访问应用时应输入的端口号
        listen       8888;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        # 所有以/api开头的请求都转发给后台服务器应用
        location ~ /api {
            rewrite  ^/api/(.*)$ /$1 break; # 重写路径. 将/api删除
            proxy_pass   http://localhost:5000; # 所需要代理到的后台服务器应用端口
        }

        # 所有请求都不匹配时转发给前台应用
        location / {
            root  D:/Vscode/workspace/admin-client_blank/build; # 前端网页所在的绝对路径 
            index  index.html index.htm; # 前端网页的入口文件
        }
        

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

3.3 访问页面

访问页面http://localhost:8888即可看到页面, 并发现功能正常

4 解决BrowserRouter 生产环境404的问题

  • 问题: 刷新某个路由路径时, 会出现404的错误.
  • 原因: 项目根路径后的path路径会被当做后台路由路径, 去请求对应的后台路由, 但没有.
  • 解决: 使用自定义中间件去读取返回index页面呈现.
app.use((req, res) => {
  fs.readFile(__dirname + '/public/index.html', (err, data)=>{
    if(err){
      console.log(err)
      res.send('后台错误')
    } else {
      res.writeHead(200, {
        'Content-Type': 'text/html; charset=utf-8',
      });
      res.end(data)
    }
  })
})