小言_互联网的博客

Vue动态生成Router

451人阅读  评论(0)

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> 

转载:https://blog.csdn.net/NSPOKS/article/details/101773455
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场