Vue动态生成Router

本文介绍了如何在Vue中使用Vue Router动态生成路由配置。基于用户登录后的资源数据,服务端返回用户可访问的菜单信息,通过路由导航守卫和全局钩子函数实现权限跳转。在前端,通过动态加载组件并格式化数据来创建符合Vue Router要求的路由对象,最终通过`addRoutes`方法将动态路由添加到路由表中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Vue路由介绍

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌,一般直观体现在页面的侧边路由中,依照RBAC模型动态地为不同用户生成不同的路由配置。

实现思路

  1. 用户登录后获取资源数据 ,向服务端发送请求,要求获取当前的菜单信息和组件信息,服务端根据当前用户所具备的角色,以及角色所对应的资源,返回一个json字符串。
  2. 后端获取json语句: 即从用户表、角色表、资源表、用户角色中间表、角色资源中间表中获取该用户可访问的资源。
<sql id="ResourceColumns">
   r1.`id`,
   r1.`name`,
   r1.`code`,
   r1.`url`,
   r1.`open_img`,
   r1.`status`,
   r2.`name` AS name2,
   r2.`code` AS code2,
   r2.`url` AS url2,
   r2.`open_img` AS open_img2,
   r2.`status` AS status2
</sql>

< select id=“getResourcesByUserId” resultMap=“ResourcesMap”>
SELECT

FROM t_resource r1, t_resource r2
WHERE r1.id=r2.parent_id AND r1.id!=1 and r2.id
in(SELECT rr.resource_id
FROM t_user_role_relationship ur,t_role_resource_relationship rr
WHERE ur.role_id=rr.role_id and ur.user_id=#{userId})
and r2.status=1 ORDER BY r1.id,r2.id

  1. 路由导航守卫 ,在store中创建一个routes数组,这是一个空数组,然后开启路由全局守卫,将返回的数据放置在store中。不是登录页面的话,我先从store中获取当前的登录状态,如果未登录,则通过路由中meta属性的requireAuth属性判断要去的页面是否需要登录,如果需要登录,则跳回登录页面,同时将要去的页面的path作为参数传给登录页面,以便在登录成功之后跳转到目标页面,如果不需要登录,则跳转过去。
  2. 用户进入其他页面时获取数据

//使用钩子函数对路由进行权限跳转
router.beforeEach((to, from, next) => {
console.log(“访问路径”+to.path)
if(to.path == ‘/login’){
next();
return;
}
const role = localStorage.getItem(‘ms_username’);
if (!role && to.path !== ‘/login’) {
console.log(“进入登录”);
next(’/login’);
} else if (to.meta.permission) {
// 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
role === ‘admin’ ? next() : next(’/403’);
} else {
console.log(“获取菜单栏”);
initMenu(router, store);
next();
}
})

  1. 前端具体调用方法如下 :在初始化菜单中,首先判断store中的数据是否存在,如果存在,说明这次跳转是正常的跳转,而不是用户按F5或者直接在地址栏输入某个地址进入的。否则就去加载菜单。拿到菜单之后,首先通过formatRoutes方法将服务器返回的json转为router需要的格式,这里主要是转component,因为服务端返回的component是一个字符串,而router中需要的却是一个组件,因此我们在formatRoutes方法中动态的加载需要的组件即可。数据格式准备成功之后,一方面将数据存到store中,另一方面利用路由中的addRoutes方法将之动态添加到路由中。

export const initMenu = (router, store)=> {
//若已经含有资源信息则不加载
if (store.state.routes.length > 0) {
return;
}
getRequest("/config/sysmenu").then(resp=> {
if (resp && resp.status == 200) {
console.log(resp.data);
var fmtRoutes = formatRoutes(resp.data);
router.addRoutes(fmtRoutes);
//将component信息存入store中
store.commit(‘initMenu’, fmtRoutes);
}
})
}
export const formatRoutes = (routes)=> {
let fmRoutes = [];
routes.forEach(router=> {
let {
url,
code,
name,
status,
openImg,
children
} = router;
if (children && children instanceof Array) {
children = formatRoutes(children);
}
let fmRouter = {
path: code,
component:resolve =>{
if (component.startsWith(“Home”)) {
require([’…/components/common/’+ code +’.vue’], resolve)
} else if (component.startsWith(“Base”)) {
require([’…/views/basedata/’+ code +’.vue’], resolve)
} else if (component.startsWith(“Sys”)) {
require([’…/views/system/’+ code +’.vue’], resolve)
} else if (component.startsWith(“Exam”)) {
require([’…/views/exam/’+ code +’.vue’], resolve)
} else if (component.startsWith(“Paper”)) {
require([’…/views/paper/’+ code +’.vue’], resolve)
}
},
name: name,
openImg: openImg,
status: status,
children: children
};
fmRoutes.push(fmRouter);
})
return fmRoutes;
}

  1. 最后在需要显示的菜单页面进行渲染:
<template v-for="(item,index) in this.routes" v-if="!item.hidden">
    <el-submenu :key="index" :index="index+''">
      <template slot="title">
        <i :class="item.iconCls" style="color: #20a0ff;width: 14px;"></i>
        <span slot="title">{{item.name}}</span>
      </template>
      <el-menu-item
        width="180px"
        style="padding-left: 30px;padding-right:0px;margin-left: 0px;width: 170px;text-align: left"
        v-for="child in item.children"
        :index="child.path"
        :key="child.path"
      >{{child.name}}</el-menu-item>
    </el-submenu>
  </template> 
### Vue动态生成路由的方法 #### 使用 `import.meta.glob` 自动加载路由配置 为了实现动态路由,在现代前端构建工具的支持下,可以利用 `import.meta.glob` 来自动扫描并导入指定目录下的所有模块。这种方法不仅简化了手动维护大量静态路由定义的工作量,还提高了项目的可扩展性和灵活性。 ```typescript // src/router/index.ts import { createRouter, createWebHistory } from 'vue-router'; import type { RouteRecordRaw } from 'vue-router'; function loadDynamicRoutes(): RouteRecordRaw[] { // 扫描 ./views 文件夹及其子文件夹内的 .ts 路由配置文件 const files: Record<string, any> = import.meta.glob('@/views/**/*.ts', { eager: true }); let routes: RouteRecordRaw[] = []; for (const path in files) { // 提取路由配置项并加入到总列表中 routes.push(...files[path].default); } return routes; } const router = createRouter({ history: createWebHistory(), routes: [ ...loadDynamicRoutes(), // 动态加载的路由表 { path: '/:pathMatch(.*)*', name: 'NotFound', component: () => import('@/components/404.vue') }, ] }); export default router; ``` 此代码片段展示了如何通过遍历视图文件夹来收集所有的路由记录,并将其注册至路由器实例中[^3]。 #### 结合权限控制实现个性化路由展示 除了基本的功能外,还可以进一步增强应用的安全性与用户体验——基于用户的登录状态或角色级别显示相应的导航链接: ```javascript async function setupUserSpecificRoutes(userRole?: string): Promise<void> { await router.isReady(); if (!userRole || userRole === 'guest') return; try { const additionalRoutesResponse = await fetch(`/api/user/${userRole}/routes`); const newRoutesData = await additionalRoutesResponse.json(); // 向现有路由树添加新的私有路由节点 router.addRoute(newRoutesData); console.log('Updated route map:', JSON.stringify(router.getRoutes())); } catch(error){ console.error("Failed to update dynamic routes:", error.message); } } ``` 上述函数会根据传入的角色参数向服务器发起请求获取额外的专属路由数据,并调用 `addRoute()` 方法即时更新客户端上的路由映射关系[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值