1.在做菜单service封装之前,我们先理清下菜单展现的完整逻辑,登录后,我们可以请求后台拿到菜单树数据,由于我们从后台拿到的菜单数据格式跟antd pro显示的格式不一致,肯定要做数据格式转换,转换以后我们把菜单数据可以像第三章的用户信息一样存入全局初始数据
2.只要存入了全局初始数据,我们可以在任何组件中直接拿到菜单数据做展现
3.整个过程看上去比较简单,实际上有蛮多坑要趟,我们一步步来
4.我们创建一个独立的菜单service文件,之前ant design pro的request请求和login都是建立在src/services/ant-design-pro/目录下,我们在src/services/ant-design-pro/创建一个独立的menu.js文件
5.将以下代码拷贝到menu.js中
import { request } from 'umi';
export async function currentUserMenus() {
return request('/api/getRouters', {
method: 'GET',
});
}
这段代码就是封装调用后台getRouters接口。
6.在menu.js中创建菜单格式转换的函数filterMenuData,代码如下
const filterMenuData = (menuData) => {
if (!menuData) {
return [];
}
const tempResult = menuData
.filter((item) => item.name && !item.hideInMenu)
.map((item) => getSubMenu(item))
.filter((item) => item);
const result = tempResult.map((item) => {
return {
...item,
name: item.meta ? item.meta.title : '',
icon: item.meta ? item.meta.icon : '',
};
});
return result;
};
这段代码主要是做格式转换的,遍历menuData,如果菜单项item有name属性且菜单不隐藏,我们让菜单的nam属性等于菜单的meta.title,icon属性等于菜单的meta.icon。getSubMenu(item)处理子菜单,getSubMenu代码如下:
const getSubMenu = (item) => {
if (item.children && !item.hideChildrenInMenu && item.children.some((child) => child.name)) {
return {
...item,
name: item.meta ? item.meta.title : '',
icon: item.meta ? item.meta.icon : '',
children: filterMenuData(item.children),
};
}
return item;
};
children: filterMenuData(item.children), 如果菜单有children,对children做递归调用。
7.我们增加一个方法,对后台请求后的数据直接做转换和递归处理,让公开出去的数据是已经转换好的菜单数据
export async function getCurrentUserMenus () {
try {
const routes = await currentUserMenus();
const menuData = filterMenuData(routes.data);
return menuData;
} catch (error) {
console.log(error);
}
return undefined;
};
getCurrentUserMenus返回的是已经做好转换的菜单数据,并且使用递归对所有的子菜单也做了转换。