React學習-數據可視化


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.html

    b. 阿里開源

  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.

然后我們知道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)

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)
        }
      })
    })
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM