Vue路由介绍
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌,一般直观体现在页面的侧边路由中,依照RBAC模型动态地为不同用户生成不同的路由配置。
实现思路
- 用户登录后获取资源数据 ,向服务端发送请求,要求获取当前的菜单信息和组件信息,服务端根据当前用户所具备的角色,以及角色所对应的资源,返回一个json字符串。
- 后端获取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
- 路由导航守卫 ,在store中创建一个routes数组,这是一个空数组,然后开启路由全局守卫,将返回的数据放置在store中。不是登录页面的话,我先从store中获取当前的登录状态,如果未登录,则通过路由中meta属性的requireAuth属性判断要去的页面是否需要登录,如果需要登录,则跳回登录页面,同时将要去的页面的path作为参数传给登录页面,以便在登录成功之后跳转到目标页面,如果不需要登录,则跳转过去。
- 用户进入其他页面时获取数据
//使用钩子函数对路由进行权限跳转
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();
}
})
- 前端具体调用方法如下 :在初始化菜单中,首先判断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;
}
- 最后在需要显示的菜单页面进行渲染:
<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