【前言】
找了不少Admin模板,最後仍是看中了AntDesignPro(下文簡寫antd pro)這個阿里巴巴開源的Admin框架,長這樣(還行吧,目前挺主流的):html
官網地址:https://pro.ant.design/index-cn前端
該套模板是使用了React開發框架做爲基礎,AntDesign(螞蟻金服開源UI組件庫)做爲UI庫,集成了Dva,Umi,Mock等庫,若是不是很瞭解這些內容,門檻仍是比較高的。es6
咱們今天須要實現一個需求:將Antd Pro模板中固定寫死的菜單換成從服務器請求菜單而後進行渲染typescript
爲啥非要本身寫,官網文檔不香嗎?----官方文檔寫的實在太草了,並且目前沒有typescript方式的文檔,須要踩多少坑...不過不要緊,看完這篇坑就都基本填平了npm
關於Antd Pro第一步,如何建立並運行Antd Pro,能夠移步 https://www.cnblogs.com/7tiny/p/13444963.html後端
【瞭解項目中的dva和Umi用法】
antd pro 默認採用了Umi和dva組件,所以想要在基礎上添加功能必須瞭解數據請求和數據流向api
在dva中主要分3層,models,services,components,其中models是最重要概念,這裏放的是各類數據,與數據交互的應該都是在這裏。services是請求後臺接口的方法。components是咱們編寫的組件。服務器
service層
service 層僅僅是封裝了用request請求服務端的api的邏輯,這裏不涉及業務邏輯,比較簡單,例以下面代碼:antd
import request from '@/utils/request'; export interface LoginParamsType { userName: string; password: string; mobile: string; captcha: string; } export function fakeAccountLogin(params: LoginParamsType) { return request('/api/login/account', { method: 'POST', data: params, }); } export async function getFakeCaptcha(mobile: string) { return request(`/api/login/captcha?mobile=${mobile}`); }
models層
models層是核心業務邏輯的所在框架
import { Effect, Reducer } from 'umi'; import { queryCurrent, query as queryUsers } from '@/services/user'; export interface CurrentUser { avatar?: string; name?: string; title?: string; group?: string; signature?: string; tags?: { key: string; label: string; }[]; userid?: string; unreadCount?: number; } export interface UserModelState { currentUser?: CurrentUser; } //定義接口 export interface UserModelType { namespace: 'user'; state: UserModelState; effects: { fetch: Effect; }; reducers: { saveCurrentUser: Reducer<UserModelState>; }; } const UserModel: UserModelType = { //命名空間,component層調用路由方法的時候須要根據命名空間匹配 namespace: 'user', //存放值的地方 state: { currentUser: {}, }, // 與後臺交互,處理數據邏輯的地方 effects: { //業務方法,這裏的_是不須要參數,若是須要參數,這裏改爲傳遞進來的參數對象便可 //這裏支持call,put,select等幾種方法,用call調用service層的方法 //const m = yield select((state) => state.test.num) //select就是用來選擇上面state裏的,這裏沒用上 *fetch(_, { call, put }) { //queryUsers是引入service層那個function的一個名字 const response = yield call(queryUsers); yield put({ // 這就是reducer中save方法, put就是用來觸發reducer的方法,payload裏就是傳過去的參數。 同時它也能觸發同等級effects中其餘方法。 type: 'saveCurrentUser', payload: response, }); }, }, // 能改變界面的action應該放這裏,這裏按官方意思不該該作數據處理,只是用來return state 從而改變界面 reducers: { //能夠理解爲一個方法 saveCurrentUser(state, action) { //return新的state,這樣頁面就會更新 es6語法,就是把state所有展開,而後把currentUser從新賦值 return { ...state, currentUser: action.payload || {}, }; }, }, }; export default UserModel;
component組件中調用model層
在某一個方法裏用dispatch便可調用
clickHandler = () => { dispatch({ type: "user/fetch",// 這裏就會觸發models層裏面effects中fetch方法(也能夠直接觸發reducer中方法,看具體狀況) ,user是命名空間名字 payload: { }, }) }
這裏注意一下type請求的方法路由便可,前面是命名空間,後面是方法名
使用connect獲取dispatch調用後改變的state中的數據
首先須要在組件接口中定義字段,類型爲model中定義的類型,由於要獲取model中字段這個值,確定是同一種類型的
而後在組件的實現中定義變量,從props中獲取值
在組件代碼下方的connect方法中將變量賦值,只有這裏賦值了,組件中的常量才能夠從props中獲取到state中的值
這裏connect方法的參數其實就是各個model中的state,dispatch後,這裏即可以獲取到修改後的值
tips:由於使用的是typescript,因此這裏的參數須要在ConnectState中先定義:
【開始改造Antd Pro,實現從服務器請求菜單】
定義service
在src/services文件夾下新增文件 menu.ts
import request from '@/utils/request'; export async function query(): Promise<any> { return request('/api/getmenu'); //這裏是服務端的獲取菜單的地址,根據本身狀況進行調整 }
定義model
在src/models文件夾下新增文件 menu.ts
import { Effect, Reducer } from 'umi'; import { MenuDataItem } from '@ant-design/pro-layout'; import { query } from '@/services/menu'; export interface MenuModelState { menuData: MenuDataItem[]; } export interface MenuModelType { namespace: 'menu'; state: MenuModelState; effects: { getMenuData: Effect; }; reducers: { saveMenuData: Reducer<MenuModelState>; }; } //這裏作了個轉換,可能服務端返回的接口格式和前端的路由格式並不一致,能夠在這個方法裏進行調整,這裏的方法僅做參考,根據本身實際狀況進行調整便可 const menuFormatter = (response: any) => { if (response === null) return []; var re = response.map((item: { name: string; route: string; children: any; }) => { const result = { children: {}, name: item.name, path: item.route === null ? '/' : item.route, }; if (item.children) { result.children = menuFormatter(item.children); } return result; }) return re; } const MenuModel: MenuModelType = { namespace: 'menu', state: { menuData: [], }, effects: { *getMenuData(_, { put, call }) { const response = yield call(query); yield put({ type: 'saveMenuData', payload: menuFormatter(response.data.viewMenu), }); }, }, reducers: { saveMenuData(state, action) { return { ...state, menuData: action.payload || [], }; }, }, }; export default MenuModel;
調整組件 BasicLayout.tsx
antd pro的菜單調整在 src/layouts/BasicLayout.tsx 文件中
這裏menuDataRender 默認指向一個方法,我這裏不要原來的方式,咱們要調整成本身的數據
如下代碼如無特殊說明,都在 BasicLayout.tsx 文件中
1. 調整接口
在 BasicLayoutProps 接口中添加承載菜單的字段
2. 調整組件傳入的字段,useEfect方法中加入請求服務的路由
3. 調整組件menuDataRender爲使用傳進來的菜單數據(之前那個方法不用了)
4. 調整connect方法,獲取數據
menu是咱們在models/menu.tx中定義的MenuModelState類型,光這裏寫會提示錯誤,咱們須要在ConnectState中先將該字段定義才能夠正常使用
【運行一下試試效果】
執行命令運行一下看看效果
cnpm start
能夠看到,已經自動觸發了後端接口,並獲取到了數據,最後又用服務端的數據渲染了菜單
其餘內容能夠參考官方文檔
antd pro官網地址:https://pro.ant.design/index-cn