视频地址:https://www.bilibili.com/video/BV11A411J7z5
1.后端返回路由的思路
1. 登录后,后端返回路由权限api列表JSON
2. 处理后端返回的JSON,转化成Vue的路由结构
3. 将静态路由结构转化成动态路由
4. 最后动态渲染菜单组件
2.前后端可以这样定义路由规则
module.exports = [
{
id: 2, // 第一层是 home,就不写了
pid: 0, // pid是零,证明他是没有父级的,他是第一层路由
path: '/course', // 路径
name: 'Course', // 组件名称
title: '课程管理' // 名子
},
{
id: 3,
pid: 2, // pid是二,证明他是有父级的,他是id为2的子路由
path: 'operate', // 路径
name: 'CourseOperate', // 组件名称
title: '课程操作', // 名子
link: '/course/operate' // 点击时候的子路由
},
{
id: 4,
pid: 3, // pid是三,证明他是有父级的,他是id为3的子路由
path: 'info_data', // 路径
name: 'CourseInfodata', // 组件名称
title: '课程数据', // 名子
link: '/course/operate/info_data' // 点击时候的子路由
},
{
id: 5,
pid: 2, // pid是二,证明他是有父级的,他是id为2的子路由
path: 'add', // 路径
name: 'CourseAdd', // 组件名称
title: '增加课程', // 名子
link: '/course/add' // 点击时候的子路由
},
{
id: 6, // 第一层是 home,就不写了
pid: 0, // pid是零,证明他是没有父级的,他是第一层路由
path: '/student', // 路径
name: 'Student', // 组件名称
title: '学生管理' // 名子
},
{
id: 7,
pid: 6, // pid是二,证明他是有父级的,他是id为6的子路由
path: 'operate', // 路径
name: 'Student/Operate', // 组件名称
title: '学生操作', // 名子
link: '/Student/Operat' // 点击时候的子路由
},
{
id: 8,
pid: 6, // pid是二,证明他是有父级的,他是id为6的子路由
path: 'add', // 路径
name: 'StudentAdd', // 组件名称
title: '增加学生', // 名子
link: '/Student/add' // 点击时候的子路由
}
]
3.面试官问后台管理权限的路由思路
一些中小型的公司的路由权限可能是这样做的,先把所有的路由写好,静态的放在路由表的里面做一个变量,然后从后端请求回数据以后,再去对比这张静态表,然后再删减,最后再合并到原本的路由当中去,实际上这样做是不对的。
真正的路由应该从后端的表里面直接取出来,然后返回给前端,前端根据定义的规则形成树(路由树),然后转成路由,最后再渲染到真正的路由上。
4.后端返回 api , 解析 看得到的 初级,中级,高级路由的权限(品好下走)
// id :1 权限等级
// 等级的称呼 没多大作用 过
// auth 里面的数字,就是当前等级能看到的路由权限,对应的是上面路由表里的id,往上翻,看明白了再回来
module.exports = [
{
id: 1, // 普通人的权限,只能看到auth里面的几个路由,细品,你细品再往下看
name: 'zhangsan',
auth:[2,3,4,7] // 这里的数字就是上面路由表里定义的id号,你细品,多品几遍想通再往下走
},
{
id: 2, // 小老板的权限,只能看到auth里面的几个路由,细品,你细品再往下看
name: 'lisi',
auth:[2,3,5,6,7,8] // 这里的数字就是上面路由表里定义的id号,你细品,多品几遍想通再往下走
},
{
id: 3, // 大老板的权限,能看到所有的路由,细品,你细品再往下看
name: 'wangwu',
auth:[2,3,4,5,6,7,8] // 这里的数字就是上面路由表里定义的id号,你细品,多品几遍想通再往下走
},
]
5.接下来的步骤还是后端处理,大概思路就是,根据登录用户的等级,对应相应auth里面的数字 id , 循环 , 与上上面定义路由表里的id对比,有相同的就返回给前端(这里是后端的思路,前端了解最好,工作了可以跟后端***)
6.再下面就到前端了,开始干活吧
// 1.前端请求数据,参数假设是 uid,其实就是用户的等级,把这个等级传给后端,后端判断当前等级返回对应的权限,就是上面的 auth 里面的路由id, 只要有的,从之前定义的路由表里拿出来,全部返回给前端就行了,剩余的交给前端形成树,这个请求是用户一登录就得请求的,前端可以把它放在App.vue 里面请求( 赶紧复习下 vuex )
// 2.调用第一步接口,uid好比传的3,返回的数据如下图,不明白的话可以看一下id 为3对象下面auth数组里的数字
// 3. 转树,转成vue的路由树,根据的是前后端共同定义的规则,忘了看第二大步(上面上面),这里要用vuex了
// state 文件
export default { // 里面三个默认
uid: 2, // 默认用户的等级
hasAuth: false, // 默认没有权限
userRouters:[] // 树形结构的数据,默认为空
}
// actions 文件 请求异步处理的地方
import { getUserRouters } from '../services'; // 这里是引用的axios的接口
import { formatRouterTree } from '../libs/utils'; // 结构化的封装方法
export default {
async setUserRouters({ commit, state }) { // async await 不会的话自己百度
const userRouters = await getUserRouters(state.uid); // 拿到返回的路由数组,就是上面的图
// 拿到返回树形结构化,可以打印看一下
// 这里把结构化的封装方法写外面了
payload = formatRouterTree(userRouters) // 调用封装方法
console.log( payload ) // 打印查看树结构是否符合
// 下面通过 mutations 把结构化后的树存到state里面
commit('setUserRouters', payload ); // 把树结构传过去,放到state里的 userRouters
commit('setAuth', true); // 改变 state 里的 hasAuth ,此时就有权限了
}
// 在 main.js里面执行上面这个方法
// import store from './stort' 有的就不用加了,没有的别忘了引入
// store.dispatch('setUserRouters')
}
// mutations.js 文件
export default {
setAuth (state, auth) {
state.hasAuth = auth;
},
setUserRouters (state, userRouters) {
state.userRouters = userRouters;
}
}
// 完事做路由了
// libs/utils.js 文件
function formatRouterTree (data) { // data 就是传过来的路由对象,如上图,在这里结构化
//
let parents = data.filter(p => pid === 0) // 拿到所有的一级路由
let children = data.filter(c => pid !== 0) // 拿到非一级路由的所有路由
dataToTree(parents, children); // 每次递归一下
//
function dataToTree (parents, children) {
parents.map((p) => { // 遍历父亲,拿出每一项
children.map((c, i) => { // 遍历儿子里面的pid是不是等于父亲的id
if (c.pid === p.id) { // 证明这个c 是 p 的儿子
let _c = JSON.parse(JSON.stringify(children)); // 深拷贝
_c.spllice(i,1); // 留下真正的自己
dataToTree([c], _c) // 再调用一遍
if (p.children) {
p.children.push(c);
} else {
p.children = [c];
}
}
})
})
}
return parents; // 返回
}
export { formatRouterTree }
// main.js 文件
import store from './stort' // 有的就不用加了,没有的别忘了引入
store.dispatch('setUserRouters') // 调用actions 方法,返回路由对象
- 渲染真正的路由上 这里还把方法写到 utils.js 里
// libs/utils.js 文件
function formatRouterTree (data) { // data 就是传过来的路由对象,如上图,在这里结构化
//
let parents = data.filter(p => pid === 0) // 拿到所有的一级路由
let children = data.filter(c => pid !== 0) // 拿到非一级路由的所有路由
dataToTree(parents, children); // 每次递归一下
//
function dataToTree (parents, children) {
parents.map((p) => { // 遍历父亲,拿出每一项
children.map((c, i) => { // 遍历儿子里面的pid是不是等于父亲的id
if (c.pid === p.id) { // 证明这个c 是 p 的儿子
let _c = JSON.parse(JSON.stringify(children)); // 深拷贝
_c.spllice(i,1); // 留下真正的自己
dataToTree([c], _c) // 再调用一遍
if (p.children) {
p.children.push(c);
} else {
p.children = [c];
}
}
})
})
}
return parents; // 返回
}
function generateRouter (userRouters) { // 真正的路由
let newRouters = userRouters.map((r) => {
let routes = {
path: r.path,
name: r.name,
component: () => import(`@/views/${r.name}`)
}
if (r.children) { // 如果有子路由
routers.children = generateRouter(r.children);
}
return routes;
})
return newRouters; // 最终路由
}
export { formatRouterTree, generateRouter }
8.main.js
// main.js 文件
import store from './stort' // 有的就不用加了,没有的别忘了引入
import { generateRouter } from '@/libs/utils' // 引入路由树
router.beforEach(async (to, form, next) => {
if (!store.state.hasAuth) { // 判断有没有权限
await store.dispatch('setUserRouters'); // 调用actions 方法,返回路由对象
const newRouters = generateRouter(store.state.userRouters);
router.addRoutes(newRoutes);
next({path: to.path})
} else { // 如果有权限
next();
}
})
9.完毕建立页面,查看效果
// 查看所有路由,建立页面 有子路由的记得加 <router-view />