如何在Vue Router初始化后为模块化后台添加插件路由?
可以用Vue Router实现动态路由的SPA,完全不需要局限于静态路由
明确说:Vue Router 完全支持登录后动态添加路由,你的模块化后台需求绝对能实现,SPA并非只能基于静态路由开发。下面是具体的实现思路和实操步骤:
一、先初始化静态路由
先把登录阶段能用的固定路由注册好,比如登录、找回密码、仪表盘、用户设置,这些路由在Vue Router初始化时就配置完成:
// router/index.js import { createRouter, createWebHistory } from 'vue-router' import Login from '@/views/Login.vue' import ForgotPassword from '@/views/ForgotPassword.vue' import Dashboard from '@/views/Dashboard.vue' import UserSettings from '@/views/UserSettings.vue' const staticRoutes = [ { path: '/login', component: Login }, { path: '/forgot-password', component: ForgotPassword }, // 需登录才能访问的路由加权限标记 { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true } }, { path: '/user-settings', component: UserSettings, meta: { requiresAuth: true } }, // 兜底路由 { path: '/:pathMatch(.*)*', redirect: '/login' } ] const router = createRouter({ history: createWebHistory(), routes: staticRoutes }) // 全局路由守卫,校验登录状态 router.beforeEach((to, from, next) => { const isLoggedIn = localStorage.getItem('token') // 按实际登录逻辑判断 if (to.meta.requiresAuth && !isLoggedIn) { next('/login') } else { next() } }) export default router
二、改造后端:返回插件路由数据
你之前用PHP遍历插件文件夹收集菜单的逻辑可以直接复用,只需调整成返回Vue Router需要的路由结构。比如每个插件的menu.php,除了原有菜单信息,补充路由名称、组件路径、子路由等字段:
// 插件pages的menu.php <?php $pluginRoute = [ 'name' => 'pages', 'path' => '/pages', 'component' => '@/plugins/Pages/Index.vue', // 对应Vue组件的路径 'meta' => [ 'title' => '页面管理', 'icon' => 'fa fa-pencil-square', 'requiresAuth' => true ], 'children' => [ [ 'name' => 'pages-list', 'path' => 'items', 'component' => '@/plugins/Pages/List.vue', 'meta' => ['title' => '页面列表'] ], [ 'name' => 'pages-add', 'path' => 'add', 'component' => '@/plugins/Pages/Add.vue', 'meta' => ['title' => '新增页面'] ], [ 'name' => 'pages-edit', 'path' => 'edit/:id', 'component' => '@/plugins/Pages/Edit.vue', 'meta' => ['title' => '编辑页面'] ] ] ]; // 将当前插件路由加入全局数组 $globalPluginRoutes[] = $pluginRoute; ?>
然后在Codeigniter 4里写一个接口,遍历所有插件的menu.php,整理后返回完整的插件路由列表:
// Codeigniter 4控制器方法:获取插件路由 public function getPluginRoutes() { $globalPluginRoutes = []; $pluginsDir = APPPATH . 'Modules/'; // 你的插件目录路径 $plugins = scandir($pluginsDir); foreach ($plugins as $plugin) { if ($plugin === '.' || $plugin === '..') continue; $menuFile = $pluginsDir . $plugin . '/menu.php'; if (file_exists($menuFile)) { include $menuFile; } } return $this->response->setJSON($globalPluginRoutes); }
三、登录后动态添加路由
用户登录成功后,调用上面的接口拿到插件路由数据,再用Vue Router的addRoute()方法动态注册路由:
// Login.vue的登录方法 async handleLogin() { // 先执行登录请求,获取token const loginRes = await this.$api.login(this.loginForm) if (loginRes.success) { localStorage.setItem('token', loginRes.token) // 请求插件路由数据 const pluginRoutes = await this.$api.getPluginRoutes() if (pluginRoutes.length) { pluginRoutes.forEach(route => { // 动态添加路由 this.$router.addRoute(route) }) } // 跳转到仪表盘 this.$router.push('/dashboard') } }
四、处理页面刷新的情况
动态路由是在浏览器端临时添加的,页面刷新后会丢失,所以要在App.vue的mounted钩子中判断:如果用户已登录,就重新获取路由并添加:
// App.vue export default { async mounted() { const isLoggedIn = localStorage.getItem('token') if (isLoggedIn) { const pluginRoutes = await this.$api.getPluginRoutes() pluginRoutes.forEach(route => { this.$router.addRoute(route) }) // 如果当前路由是兜底的404,重定向到仪表盘 if (this.$router.currentRoute.value.path === '/:pathMatch(.*)*') { this.$router.push('/dashboard') } } } }
五、动态生成侧边菜单
直接用拿到的路由数据渲染菜单就行,因为路由的meta字段里已经包含了菜单标题、图标这些信息:
<!-- SideMenu.vue --> <template> <aside class="sidebar"> <nav> <div v-for="route in pluginRoutes" :key="route.name" class="menu-item"> <router-link :to="route.path"> <i :class="route.meta.icon"></i> <span>{{ route.meta.title }}</span> </router-link> <!-- 渲染子菜单 --> <div v-if="route.children" class="sub-menu"> <router-link v-for="child in route.children" :key="child.name" :to="`${route.path}/${child.path}`" > {{ child.meta.title }} </router-link> </div> </div> </nav> </aside> </template> <script> export default { data() { return { pluginRoutes: [] } }, async mounted() { const isLoggedIn = localStorage.getItem('token') if (isLoggedIn) { this.pluginRoutes = await this.$api.getPluginRoutes() } } } </script>
几个注意点
- 组件懒加载:插件组件建议用懒加载减少初始打包体积,比如
component: () => import('@/plugins/Pages/Index.vue') - 路由命名唯一:确保每个插件的路由
name不重复,避免冲突 - 权限控制:可以在路由
meta里加权限标识,结合路由守卫实现角色权限控制
内容的提问来源于stack exchange,提问作者Anton
相关产品推荐
相关产品推荐

