1 动态菜单
技术思路:配置路由,用户登录后根据用户信息获取后台菜单。
2 动态路由+动态菜单
技术思路: 使用umijs的运行时修改路由 patchRoutes({ routes }) UMIJS 参考文档 ,react umi 没有守护路由的功能 直接在 app.tsx 的 layout 下的 childrenRender 添加守护路由 实现登录后的菜单路由增加。登录后的菜单由登录接口 加个menu参数获取。 默认路由+动态登录路由+动态菜单
具体操作
- 1. 动态菜单:
文件:/src/app.tsx
找到 layout 插入 menu
menu: {
locale: false,
params: {
userId: initialState?.currentUser?.userid,//引起菜单请求的参数
},
request: async (params, defaultMenuData) => {
const { data } = await getAuthRoutes();
return loopMenuItem(data);
},
},
完全版:
/**
* 映射菜单对应的图标
* */
const loopMenuItem = (menus: MenuDataItem[]): MenuDataItem[] =>
menus.map(({ icon, routes, ...item }) => ({
...item,
icon: icon && <Icon component={icons[icon]} />,
routes: routes && loopMenuItem(routes),
})
);
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
const onCollapse = (collapsed: boolean): void => {
setInitialState({ ...initialState, collapsed }).then();
};
const onSettings = (settings: any): void => {
setInitialState({ ...initialState, settings }).then();
};
return {
// 自定义头内容的方法 我把 自定义侧边栏收缩按钮位置 方在这里
headerContentRender: () => (
<HeaderContent collapse={initialState?.collapsed} onCollapse={onCollapse} />
),
rightContentRender: () => <RightContent onSettings={onSettings} />,
disableContentMargin: false,
waterMarkProps: {
content: initialState?.currentUser?.name,
},
// 去掉系统自带
collapsedButtonRender: false,
// 指定配置collapsed
collapsed: initialState?.collapsed,
footerRender: () => <Footer />,
onPageChange: () => {
const { location } = history;
// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== loginPath) {
history.push(loginPath);
}
},
menu: {
locale: false,
params: {
userId: initialState?.currentUser?.userid,//引起菜单请求的参数
},
request: async (params, defaultMenuData) => {
const { data } = await getAuthRoutes();
return loopMenuItem(data);
},
},
links: isDev
? [
<Link key="openapi" to="/umi/plugin/openapi" target="_blank">
<LinkOutlined />
<span>OpenAPI 文档</span>
</Link>,
<Link to="/~docs" key="docs">
<BookOutlined />
<span>业务组件文档</span>
</Link>,
]
: [],
menuHeaderRender: undefined,
// 自定义 403 页面
// unAccessible: <div>unAccessible</div>,
// 增加一个 loading 的状态
childrenRender: (children, props) => {
// if (initialState?.loading) return <PageLoading />;
const { location, route } = props;
return (
<>
{children}
{/* {!props.location?.pathname?.includes('/login') && (
<SettingDrawer
disableUrlParams
enableDarkTheme
settings={initialState?.settings}
onSettingChange={(settings) => {
setInitialState((preInitialState) => ({
...preInitialState,
settings,
}));
}}
/>
)} */}
</>
);
},
...initialState?.settings,
};
};
- 2. 动态路由+动态菜单
技术思路:
使用umijs的运行时修改路由 patchRoutes({ routes }) UMIJS 参考文档 ,react umi 没有守护路由的功能 直接在 app.tsx 的 layout 下的 childrenRender 添加守护路由 实现登录后的菜单路由增加。登录后的菜单由登录接口 加个menu参数获取。 默认路由+动态登录路由
文件:config/config.ts
// https://umijs.org/config/
import { defineConfig } from 'umi';
import { join } from 'path';
import defaultSettings from './defaultSettings';
import proxy from './proxy';
import routes from './routes';
const { REACT_APP_ENV } = process.env;
export default defineConfig({
hash: true,
antd: {},
dva: {
hmr: true,
},
layout: {
// https://umijs.org/zh-CN/plugins/plugin-layout
locale: false,
siderWidth: 208,
...defaultSettings,
},
// https://umijs.org/zh-CN/plugins/plugin-locale
locale: {
// default zh-CN
default: 'zh-CN',
antd: true,
// default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: true,
},
dynamicImport: {
loading: '@ant-design/pro-layout/es/PageLoading',
},
targets: {
ie: 11,
},
// umi routes: https://umijs.org/docs/routing
routes,
access: {},
// Theme for antd: https://ant.design/docs/react/customize-theme-cn
theme: {
// 如果不想要 configProvide 动态设置主题需要把这个设置为 default
// 只有设置为 variable, 才能使用 configProvide 动态设置主色调
// https://ant.design/docs/react/customize-theme-variable-cn
'root-entry-name': 'variable',
},
// esbuild is father build tools
// https://umijs.org/plugins/plugin-esbuild
esbuild: {},
title: false,
ignoreMomentLocale: true,
proxy: proxy[REACT_APP_ENV || 'dev'],
manifest: {
basePath: '/',
},
// Fast Refresh 热更新
fastRefresh: {},
openAPI: [
{
requestLibPath: "import { request } from 'umi'",
// 或者使用在线的版本
// schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json"
schemaPath: join(__dirname, 'oneapi.json'),
mock: false,
},
{
requestLibPath: "import { request } from 'umi'",
schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json',
projectName: 'swagger',
},
],
nodeModulesTransform: {
type: 'none',
},
mfsu: {},
webpack5: {},
exportStatic: {},
});
文件:config/routes.ts
import type { MenuDataItem } from '@ant-design/pro-layout';
export default [
{
path: '/user',
layout: false,
routes: [
{
path: '/user/login',
layout: false,
name: 'login',
component: '@/pages/modules/user/Login',
},
{
path: '/user/openlogin',
layout: false,
name: 'login',
component: '@/pages/modules/user/openlogin',
},
{
path: '/user',
redirect: '@/pages/modules/user/login',
},
{
name: 'register-result',
icon: 'smile',
path: '/user/register-result',
component: '@/pages/modules/user/register-result',
},
{
name: 'register',
icon: 'smile',
path: '/user/register',
component: '@/pages/modules/user/register',
}
]
},
{
path: '/',
component: './layouts/commonLayout',
flatMenu: true,
routes: [
// {
// path: '/welcome',
// name: '工作台',
// component: '@/pages/modules/welcome',
// }
]
},
{
component: '404',
},
];
app.tsx
let extraRoutes;
export function patchRoutes({ routes }) {
if (extraRoutes) {
// extraRoutes.forEach((element: any) => {
routes.forEach((route: any) => {
if (route.path == "/") {
route.routes = mergeRoutes(extraRoutes);
}
});
// });
}
console.log("--------------------路由-------------------------", routes);
}
// export function render(oldRender) {
// getMenu().then((res: any) => {
// if (res.code == 200) {
// extraRoutes = res.result;
// oldRender();
// } else {
// history.push('/login');
// oldRender()
// }
// });
// }
// /**
// * 映射菜单对应的图标
// * */
// const loopMenuItem = (menus: MenuDataItem[]): MenuDataItem[] =>
// menus.map(({ icon, routes, ...item }) => ({
// ...item,
// icon: icon && <Icon component={icons[icon]} />,
// routes: routes && loopMenuItem(routes),
// })
// );
/**
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state
* */
export async function getInitialState(): Promise<{
settings?: Partial<LayoutSettings>;
currentUser?: API.CurrentUser;
loading?: boolean;
collapsed?: boolean;
// menuData?: MenuDataItem[] | undefined;
fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
}> {
const fetchUserInfo = async () => {
try {
const msg = await queryCurrentUser();
return msg.data;
} catch (error) {
// 跳转到指定路由
history.push(loginPath);
}
return undefined;
};
// 如果不是登录页面,执行
if (history.location.pathname !== loginPath) {
const currentUser = await fetchUserInfo();
return {
fetchUserInfo,
currentUser,
settings: defaultSettings,
};
}
return {
fetchUserInfo,
settings: defaultSettings,
};
}
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
const onCollapse = (collapsed: boolean): void => {
setInitialState({ ...initialState, collapsed }).then();
};
const onSettings = (settings: any): void => {
setInitialState({ ...initialState, settings }).then();
};
return {
// 自定义头内容的方法 我把 自定义侧边栏收缩按钮位置 方在这里
headerContentRender: () => (
<HeaderContent collapse={initialState?.collapsed} onCollapse={onCollapse} />
),
rightContentRender: () => <RightContent onSettings={onSettings} />,
disableContentMargin: false,
waterMarkProps: {
content: initialState?.currentUser?.name,
},
// 去掉系统自带
collapsedButtonRender: false,
// 指定配置collapsed
collapsed: initialState?.collapsed,
footerRender: () => <Footer />,
onPageChange: () => {
const { location } = history;
// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== loginPath) {
history.push(loginPath);
}
},
// menuDataRender: () => { return fixMenuItemIcon(initialState.menuData) },
menu: {
locale: false,
params: {
userId: initialState?.currentUser?.userid,//引起菜单请求的参数
},
request: async (params, defaultMenuData) => {
// const msg = await getMenu();
return fixMenuItemIcon(initialState?.currentUser?.menu);
},
},
links: isDev
? [
<Link key="openapi" to="/umi/plugin/openapi" target="_blank">
<LinkOutlined />
<span>OpenAPI 文档</span>
</Link>,
<Link to="/~docs" key="docs">
<BookOutlined />
<span>业务组件文档</span>
</Link>,
]
: [],
menuHeaderRender: undefined,
// 自定义 403 页面
// unAccessible: <div>unAccessible</div>,
// 增加一个 loading 的状态
childrenRender: (children, props) => {
// if (initialState?.loading) return <PageLoading />;
const { location, route } = props;
if (history.location.pathname !== loginPath && initialState?.currentUser?.menu) {
// 路由守卫
// const msg = await getMenu();
extraRoutes = initialState?.currentUser?.menu;
console.log("--------------------路由01-------------------------", extraRoutes);
patchRoutes(route);
}
return (
<>
{children}
{/* {!props.location?.pathname?.includes('/login') && (
<SettingDrawer
disableUrlParams
enableDarkTheme
settings={initialState?.settings}
onSettingChange={(settings) => {
setInitialState((preInitialState) => ({
...preInitialState,
settings,
}));
}}
/>
)} */}
</>
);
},
...initialState?.settings,
};
};
src/utils/fixMenuItemIcon.tsx
import React from 'react';
import type { MenuDataItem } from '@ant-design/pro-layout';
import * as allIcons from '@ant-design/icons';
const fixMenuItemIcon = (menus: MenuDataItem[], iconType = 'Outlined'): MenuDataItem[] => {
menus.forEach((item) => {
const { icon, routes } = item
if (typeof icon === 'string' && icon != null) {
const fixIconName = icon.slice(0, 1).toLocaleUpperCase() + icon.slice(1) + iconType
// eslint-disable-next-line no-param-reassign
item.icon = React.createElement(allIcons[fixIconName] || allIcons[icon])
}
// eslint-disable-next-line no-param-reassign,@typescript-eslint/no-unused-expressions
routes && routes.length > 0 ? item.routes = fixMenuItemIcon(routes) : null
});
return menus
};
export default fixMenuItemIcon;
src/utils/roles.tsx
文章来源:https://www.toymoban.com/news/detail-406501.html
// import { getUserPerm } from '@/services/menu';
// import router from 'umi/router';
import React from 'react';
import Icon from '@ant-design/icons';
import * as icons from '@ant-design/icons';
import { dynamic, RunTimeLayoutConfig } from 'umi';
import { SmileOutlined, HeartOutlined } from '@ant-design/icons'
export function mergeRoutes(routes) {
if (!Array.isArray(routes)) return [];
return routes.map(route => {
let module = route.component;
if (route.component) {
route.component = (component => {
if (typeof component === 'object') {
return component;
}
// 封装一个异步组件
return dynamic({
loader: () => import(`../pages/${module}/index.tsx`)
});
})(route.component);
}
if (route.routes) {
route.routes = mergeRoutes(route.routes);
}
return route;
});
}
注意: 登陆子模块要 符合 /src/pages/ 模块名称 /index.tsx 的组合文章来源地址https://www.toymoban.com/news/detail-406501.html
到了这里,关于ant design pro v5 - 03 动态菜单 动态路由(配置路由 动态登录路由 登录菜单)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!