1 可視化圖表
1.1 常用數據可視化圖標庫
-
echarts
b. 百度開源, 如果要在react項目中使用, 需要下載echarts-for-react
-
G2
a. https://antv.aplipay.com/zh-ch/g2/3.x/index.html
b. 阿里開源
-
bizcharts
a. https://bizcharts,net/products/bizCharts
b. 基於react包裝G2的開源庫
c. 需要額外下載 @antv/data-set
-
d3
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) } }) })