Ant Design Pro V4.5 从服务器请求菜单(typescript版)

千金一刻莫空度,老大无成空自伤。这篇文章主要讲述Ant Design Pro V4.5 从服务器请求菜单(typescript版)相关的知识,希望能为你提供帮助。
?Ant Design Pro V4.5 从服务器请求菜单(typescript版)
第一章、初识菜单因为我使用的ant design pro用的不是js脚本,而是ts脚本,项目菜单项在config文件夹下的rooutes.ts中

export default [ { path: \'/\', component: \'../layouts/BlankLayout\', routes: [ { path: \'/user\', component: \'../layouts/UserLayout\', routes: [ { name: \'login\', path: \'/user/login\', component: \'./user/login\', }, ], }, 此处省略n行... }, ], }, { component: \'./404\', }, ];

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

我们想用后端生成,查看官方资料,没弄懂官方的方法
官方的讲解
https://pro.ant.design/zh-CN/docs/advanced-menu
Github前端源码
https://github.com/ant-design/ant-design-pro
由于才疏识浅没弄懂官方的办法,那么就用自己的办法来实现
第二章、了解项目中的dva和Umi用法antd pro 默认采用了Umi和dva组件,因此想要在基础上添加功能必须了解数据请求和数据流向,在dva中主要分3层,models,services,components,其中models是最重要概念,这里放的是各种数据,与数据交互的应该都是在这里。services是请求后台接口的方法。components是我们编写的组件。
service 层仅仅是封装了用request请求服务端的api的逻辑,这里不涉及业务逻辑,比较简单,例如下面代码:
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}`); }

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

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;

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

component组件中调用model层,在某一个方法里用dispatch即可调用,这里注意一下type请求的方法路由即可,前面是命名空间,后面是方法名
clickHandler = () => { dispatch({ type: "user/fetch",// 这里就会触发models层里面effects中fetch方法(也可以直接触发reducer中方法,看具体情况) ,user是命名空间名字 payload: {}, }) }

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

第三章、修改代码使用后台传生成的菜单数据首先需要在组件接口中定义字段,类型为model中定义的类型,因为要获取model中字段这个值,肯定是同一种类型的,修改BasicLayout.tsx文件
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
然后在组件的实现中定义变量,从props中获取值
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
在组件代码下方的connect方法中将变量赋值,只有这里赋值了,组件中的常量才可以从props中获取到state中的值
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
这里connect方法的参数其实就是各个model中的state,dispatch后,这里便可以获取到修改后的值tips:因为使用的是typescript,所以这里的参数需要在ConnectState中先定义,文件名connect.d.ts,在src-> models文件夹下:
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
引入import { MenuModelState } from \'@/.umi/plugin-dva/connect\';
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
在src/services文件夹下新增文件 menu.ts
import request from \'@/utils/request\'; import routesTest from \'../../config/routesTest\' export async function queryTest(): Promise< any> { return routesTest; }

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

先使用routes.ts中的数据模拟服务器返回的数据,在config目录下创建routesTest.ts文件,内容如下
export default [ { path: \'/\', redirect: \'/list\', }, { name: \'offline-statistic\', path: \'/list\', component: \'./Statistic\', }, { name: \'host\', path: \'/host\', component: \'./Hosts\', } ]

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

在src/models文件夹下新增文件 menu.ts
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
代码如下
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;

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

antd pro的菜单调整在 src/layouts/BasicLayout.tsx 文件中
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
这里menuDataRender 默认指向一个方法,我这里不要原来的方式,我们要调整成自己的数据,改成如下menuDataRender={menuData},如果不行改成menuDataRender={()=> menuData}
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
添加初始加载
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
保存运行,菜单成功使用routesTest中的数据进行加载,如果图标没有显示请查看我的另一篇文章
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
测试过程发现了一个问题,退出再登陆菜单正常显示,刷新后菜单消失了,刷新后菜单不显示,菜单数据还加载了,解决办法就是重新加载菜单或页面后,执行一次history.push(\'/\'); 因为我发现菜单消失后,点击菜单的头,菜单就会加载出来了,好神奇不是
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
修改代码如下
useEffect(() => { if (dispatch) { dispatch({ type: \'user/fetchCurrent\', }); dispatch({ type: \'menu/getMenuData\', callback(){ history.push(\'/\'); }, }); } }, []);

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

namespace: \'menu\', state: { menuData: [], },effects: { *getMenuData(input, { put, call }) { const {callback} = input; const response = yield call(queryTest); yield put({type: \'saveMenuData\',payload: menuFormatter(response),}); callback(); }, },

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

然后就可以尝试使用后端传过来的数据进行菜单加载了
export async function query(): Promise< any> { return request(\'/api/services/app/UserMenuService/GetUserMenuData\'); }

Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片

完美
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
Ant Design Pro V4.5 从服务器请求菜单(typescript版)

文章图片
?
【Ant Design Pro V4.5 从服务器请求菜单(typescript版)】?

    推荐阅读