前言
最近在写自己的个人网站,需要实现一个动态菜单的功能,大致想法是,后端返回登录用户拥有权限菜单,前端根据菜单动态的创建路由。这样前端就不需要本地配置路由表了。
原理
借助vite的import.meta.glob<{ default: React.ComponentType<any> }>('../pages/**/*.tsx');
方法动态导入组件。通过这个方法,我们可以拿到文件路径和文件模块的对象,如下图所示:
我们可以配合React的lazy函数,实现组件的动态导入。
其中
shouldAddRoutes
是后端传来的登录用户的菜单列表,这样我们就能实现前端路由的动态导入了。
主要代码
tsx
// 通过vite引入Pages下所有的tsx文件
const modules = import.meta.glob<{ default: React.ComponentType<any> }>('../pages/**/*.tsx');
// 在权限列表中获取当前用户权限,本系统使用zustand进行保存
const { menus } = usePermissionStore();
// 筛选出需要添加路由的菜单
const shouldAddRoutes = menus.filter((m) => m.path && m.component);
const routes = [
...DEFAULT_ROUTER,
{
path: '/',
element: <BaseLayout />,
errorElement: <ErrorPage />,
children: shouldAddRoutes.length
? [
{
path: '/',
element: <Home />,
index: true,
},
{
path: '/un-auth',
element: <UnAuthPage />,
},
...shouldAddRoutes.map((route) => {
// 根据路径获取组件,这里只使用了Component,如需要也可以配合react-router的loader
const Component = lazy(modules[route.component]);
return {
path: route.path,
handle: {
title: route.name,
},
element: <Component />,
};
}),
]
: [],
},
{
path: '*',
element: <NotFoundPage />,
},
];
const router = createBrowserRouter(routes);
return (
<Suspense fallback={<LoadingPage message="loading..." />}>
<RouterProvider router={router} />
</Suspense>
);