項目預覽地址css
相信不少小夥伴都有可能碰到開發後臺管理系統這樣的需求,那麼咱們該如何快速的完成這個需求呢html
本文將以 react
爲切入點,記錄打造一個基礎管理系統模板的過程,以此加深對 react
技術棧以及項目實戰的理解,但願對你們開發一個這樣的項目有所幫助前端
若是文章中有出現紕漏、錯誤之處,還請看到的小夥伴多多指教,先行謝過react
如下↓webpack
react-admin
是由 create-react-app
腳手架快速構建,基於 React
生態系統搭建的後臺管理系統模板。實現了登錄/註銷、路由懶加載、axios
封裝、簡單權限管理等功能,它能夠幫助你快速生成管理系統模板,你只須要添加具體業務代碼便可ios
線上預覽地址 預覽地址git
GitHub
代碼 代碼地址es6
此項目涉及的技術棧主要有 es6
、react
、react-router
、redux
、react-redux
、Create React App
、react-loadable
、axios
等,因此你可能須要提早了解這些知識,這樣會對你瞭解這個項目有很大的幫助github
UI
展現echarts
全屏展現axios
封裝├── public # 不參與編譯的資源文件
├── src # 主程序目錄
│ ├── api # axios 封裝
│ ├── assets # 資源文件
│ │ ├── font # 字體文件
│ │ └── images # 圖片資源
│ ├── components # 全局公共組件
│ │ ├── CustomBreadcrumb # 麪包屑導航
│ │ └── CustomMenu # menu 菜單
│ ├── contatiners # 頁面結構組件
│ ├── routes # 路由目錄
│ ├── store # redux 配置
│ ├── style # 樣式目錄
│ ├── utils # 工具類
│ ├── views # UI 頁面
│ ├── APP.js # App.js
│ └── index.js # index.js
├── .prettierrc.js # 代碼規範
├── config-overrides.js # antd 樣式按需加載
複製代碼
打造一個任何一個項目,除去前期須要考慮的受衆羣體(其實就是兼容…)以外,再加上技術選型,以後就到了頁面架構層。在這個項目中,前期不在咱們的考慮範圍以內(已經肯定了有木有),因此就從頁面架構開始web
一個後臺管理項目,不管它是否具備權限校驗功能,可是有一些公共的部分是應該有的。好比登錄頁面、公共的頭部、側邊欄導航、底部以及錯誤頁面等。這些共有的部分以及權限特有
的部分共同組成了這個系統
劃分出這樣的模塊以後,一個項目基本的頁面架構也就完成了,由於這一部分關係到咱們以後對於頁面路由的定義,因此我認爲是很重要的一部分
基於
react-router@5.1.1
路由功能能夠說是一個 React
項目的關鍵,經過前面對於頁面架構的劃分,咱們就能夠很流暢的進行路由的註冊
在 react-admin
這個項目中,所使用的是 <HashRouter>
首先,咱們須要區分公共頁面和可能的特有頁面
<Router>
<Switch>
<!--精確匹配是否是在首頁-->
<Route path='/' exact render={() => <Redirect to='/index' />} />
<!-- 錯誤頁面 -->
<Route path='/500' component={View500} />
<Route path='/login' component={Login} />
<Route path='/404' component={View404} />
<!-- UI頁面 -->
<Route path='/' component={DefaultLayout} />
</Switch>
</Router>
複製代碼
接下來就能夠去註冊路由表,再將它循環遍歷到咱們的視口頁面上。你們可能也發現了循環遍歷
這個詞,操做數組就意味着咱們能夠對它進行一系列的篩選,從而實現 路由權限 的控制(這個咱們後面再說)
做爲一個 SPA
級應用,有不少優點(響應速度更快、良好的先後端分離等等),可是也存在不少缺陷,首次加載耗時過長就是咱們不得不面對的問題
其實從 webpack4.0
開始,它自己已經實現了按需加載組件,可是也有它本身的一些規則(好比文件大小),因此咱們仍是須要對頁面的首次加載進行一些處理,而路由就是一個很好的切入點
本項目使用的是 react-loadable
,它能夠用很簡單的方式實現路由的懶加載,設置延遲時間、加載動畫、服務端渲染等功能
import Loadable from 'react-loadable';
import Loading from './my-loading-component'; // 這裏能夠放置你的 loading
const LoadableComponent = Loadable({
loader: () => import('./my-component'),
loading: Loading,
});
export default class App extends React.Component {
render() {
return <LoadableComponent/>;
}
}
複製代碼
固然,你也可使用 React.lazy
和 Suspense
技術(傳送門),不過,它不支持服務端渲染
登陸的邏輯也很簡單:
咱們的項目首頁通常狀況下是 index
頁面,這個時候咱們就須要先去判斷一個用戶加載進來的時候是否是在登陸狀態,若是是那麼就正常顯示,若是不是就應該跳轉到登陸頁面
本項目使用的是將用戶的登陸信息存儲在 localStorage
中,註銷的時候清除 localStorage
關於 token
能夠直接存在本地,後臺設定一個過時時間就能夠了
還有一種狀況就是用戶登陸以後,可是因爲長時間沒有操做致使 token
過時了,這個時候可能就會出現兩種選擇:
token
,讓其繼續操做,反之則跳轉到登陸頁面(這個取決於你將用戶信息存儲在哪裏)固然,具體要怎麼作,仍是取決於產品的需求,這裏只是提供一種思路
項目使用 axios
與後臺進行交互,封裝的部分有添加請求攔截器、響應攔截器、設置響應時間以及將 token
添加到請求頭等功能
import axios from 'axios'
// 這裏取決於登陸的時候將 token 存儲在哪裏
const token = localStorage.getItem('token')
const instance = axios.create({
timeout: 5000
})
// 設置post請求頭
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
// 添加請求攔截器
instance.interceptors.request.use(
config => {
// 將 token 添加到請求頭
token && (config.headers.Authorization = token)
return config
},
error => {
return Promise.reject(error)
}
)
// 添加響應攔截器
instance.interceptors.response.use(
response => {
if (response.status === 200) {
return Promise.resolve(response)
} else {
return Promise.reject(response)
}
},
error => {
// 相應錯誤處理
// 好比: token 過時, 無權限訪問, 路徑不存在, 服務器問題等
switch (error.response.status) {
case 401:
break
case 403:
break
case 404:
break
case 500:
break
default:
console.log('其餘錯誤信息')
}
return Promise.reject(error)
}
)
export default instance
複製代碼
這裏並無對 baseUrl
進行設置,主要是考慮到項目中可能存在不止一個 url
,好比圖片這些資源可能存在七牛雲或者阿里雲這樣的服務器上面,然後臺接口又是另一個url
了。因此添加了一個 config
文件,導出各個 url
// 考慮到網站可能有好幾個域名,因此單獨提出來
export const API = 'http://rap2api.taobao.org/app/mock/234047'
export const URLAPI = ''
複製代碼
調用接口的時候就能夠直接這樣
import {API} from './api/config'
import axios from './api'
axios.get({
url: API + '/login'
})
複製代碼
固然,若是你並無這樣的需求,你徹底能夠取消 config
這個文件,將 baseUrl
一併封裝進去
一樣的,也並無對經常使用的請求好比 get
、post
等進行封裝,由於使用這些方式的時候可能會對數據作一些特定的操做,好比序列化等等,因此我的感受意義並非很大
這裏順便記錄一下跨域問題的解決方式:
若是你沒有使用 npm run eject
將 webpack
的配置暴露出來,能夠直接在 package.json
中配置 proxy
"proxy": {
"/api": {
"target": "http://100.100.100.100", //後端地址
"changeOrigin": true
}
}
複製代碼
這樣只須要在 baseUrl
後面添加 /api
就能夠了
固然,若是你將 webpack
中的配置暴露出來了,那麼也能夠直接在 config
文件中進行設置,都是能夠實現一樣的效果
權限功能基本上是後臺管理項目中不可或缺的部分
通常狀況下,權限的控制體如今頁面級別以及按鈕級別(用戶是否能夠訪問某個頁面或者操做某個按鈕,好比新增、刪除),這個權限在用戶註冊、分配或者後期超級管理員更改的時候肯定
在這個項目中使用簡單的權限控制,但願能夠給你們一些思路,具體實現方式:
menu
菜單進行過濾,渲染到頁面getMenu = menu => {
let newMenu,
auth = JSON.parse(localStorage.getItem('user')).auth // 獲取存儲的用戶權限標識
if (!auth) {
return menu
} else {
// 過濾註冊的 menu
newMenu = menu.filter(res => res.auth && res.auth.indexOf(auth) !== -1)
return newMenu
}
}
複製代碼
{routes.map(item => {
return (
<Route key={item.path} path={item.path} exact={item.exact} render={props =>
!auth ? (
<item.component {...props} />
) : item.auth && item.auth.indexOf(auth) !== -1 ? (
<item.component {...props} />
) : (
// 這裏也能夠跳轉到 403 頁面
<Redirect to='/404' {...props} />
)
}></Route>
)
})}
複製代碼
說明:這裏對註冊的路由數組進行過濾這一步進行說明,通常狀況下前端路由都是提早註冊好的,就算沒有 menu
菜單導航,若是咱們在地址欄直接輸入路徑也是能夠訪問的,這裏進行一次過濾以後就能夠避免這種狀況。固然,咱們也能夠給每個權限設定一個能夠訪問的路徑數組,經過比較跳轉的地址是否存在這個數組當中來進行相應的展現
這裏也簡單說一下後臺控制權限的案例,對於前端來講要簡單不少
menu
數組,直接渲染到頁面(對菜單的篩選由後臺完成)至於用戶在地址欄直接輸入地址去訪問,這裏有兩種狀況:
token
請求後臺數據的時候必定是不成功的,咱們能夠將這一個操做封裝在 axios
請求中,經過不一樣的狀態碼進行頁面跳轉固然,這裏的第二種狀況不多見…
項目中還集成了平時可能會遇到的一些功能需求
動畫使用的是 Animate.css
動畫庫,使用方式
// 下載
yarn add animate.css
// link標籤引入
<link rel="stylesheet" href="animate.min.css">
// 或者 import 引入
import 'animate.css'
複製代碼
而後在須要的盒子上面添加相應的類名便可,能夠設置入場、離場動畫,也能夠設置動畫時間、延時等
富文本編輯器使用的是 Antd
官方推薦的 braft-editor
一個基於
draft-js
的Web
富文本編輯器,適用於React
框架,兼容主流現代瀏覽器
使用方式:
// 引入
import BraftEditor from 'braft-editor'
// 可使用 BraftEditor.createEditorState 方法來將 raw 或者 html 格式的數據轉換成 editorState 數據
editorState: BraftEditor.createEditorState('你好,<b>可愛的人! 很幸運在這裏與你相遇!</b>')
複製代碼
更多具體的組件屬性及實例方法,你們能夠參考其文檔 傳送門
echarts
相信你們不會陌生,百度的文檔也很清晰,這裏單獨提出來主要記錄開發過程當中遇到的一個問題
在頁面窗口變化的狀況下咱們可使用
window.addEventListener('resize', function() {
myChart.resize()
})
複製代碼
這種方式保證 echarts
的正常自適應
但是當咱們在點擊菜單收縮展開按鈕的時候並不會觸發 window.resize
方法,其實頁面盒子的寬度已經發生了變化,只是 echarts
的 resize
事件已經觸發結束了,這個時候咱們只須要在 componentDidUpdate
這個生命週期中註冊一個定時器延時觸發 resize
事件就解決了,只是別忘了在 componentWillUnmount
生命週期中清除掉這個定時器
加載進度條使用的是 nprogress
,使用方式也很簡單
// 下載
yarn add nprogress
// 引入
import NProgress from 'nprogress'
// 開始加載
NProgress.start();
// 加載結束
NProgress.done();
// 移除進度條
NProgress.remove();
複製代碼
全屏功能使用的是 screenfull
插件
使用方式
// 下載
yarn add screenfull
if (screenfull.isEnabled) {
screenfull.request(); // 全屏
}
.exit() // 退出
.toggle() // 可切換
複製代碼
也能夠給它 註冊 change
事件
if (screenfull.isEnabled) {
screenfull.on('change', () => {
console.log('Am I fullscreen?', screenfull.isFullscreen ? 'Yes' : 'No');
});
}
複製代碼
可是別忘了移除掉這個事件
screenfull.off('change', callback);
複製代碼
Create React App
提供了一組最多見的錯誤規則,在代碼運行的時候會有錯誤信息提示,因此 Eslint
規則在這裏並非必須的,若是你也想在代碼書寫的時候就提示錯誤能夠進行下面這個步驟:
下載
eslint
yarn add eslint
複製代碼
添加一個
.eslintrc.js
文件或者在package.json
文件中的eslintConfig
對象中直接添加你須要使用的規則
更多規則能夠參考這裏
項目中並無使用 eslint
,只是添加了 pretter
爲項目統一了編碼風格
至於如何在項目中集成 pretter
,具體的使用方式能夠參考 官方文檔,這裏就不在敘述了
相信你們在開發這樣的項目的時候,確定或多或少會有一些定製化的東西須要修改 webpck
的配置
當咱們使用 create react app
建立項目的時候,webpack
的配置默認是不暴露出來的,若是咱們想修改它的配置,可使用 yarn eject
或者 npm run eject
命令將其暴露出來再去修改
可是,若是咱們並不想暴露 webpack
的配置,還想去配置它該怎麼辦呢
antd
的樣式按需加載就是經過這種方式實現的
react-app-rewired
是react
社區開源的一個修改CRA
配置的工具,例如擴展Create React
App
的Webpack
配置,而customize-cra
提供了一組用於自定義利用react-app-rewired
核心功能的Create React App
配置, 能夠經過config-overrides.js
文件來對webpack
配置進行擴展
簡單點: 使用 react-app-rewired
和 customize-cra
能夠實現咱們的需求
使用方式:
config-overrides.js
文件// 文件裏面這麼寫,好比說咱們設置一個絕對路徑
const { override, addWebpackAlias } = require('customize-cra')
const path = require('path')
module.exports = override(
addWebpackAlias({
['@']: path.resolve(__dirname, 'src')
})
)
複製代碼
package.json
文件中的 scripts
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
}
複製代碼
結束,這樣咱們就能夠在項目中愉快地使用這個 @
了
固然,customize-cra
這個包爲咱們還提供了不少封裝好的 API
,詳情請 參見這裏
這個項目都是本人閒暇時間開發,主要是爲了熟悉 react
開發流程以及其周邊生態的使用,項目仍是比較簡陋,後期會進行迭代開發,將其打形成一個更加實用的後臺管理模板
若是以爲不錯或者對你有些許的幫助,歡迎 star
,或者你有更好的實現方式、有趣的 idea
,也歡迎留言交流
最後,推薦一下本人的前端學習歷程文檔,裏面分享了許多前端知識的小片斷 點擊這裏 進行查看, 歡迎 star
關注