感谢这篇文章:https://blog.csdn.net/weixin_34179968/article/details/92579951
网上找到了好多文章就这篇靠谱点,只少能靠这篇文章把功能做出来。唯一缺点就是提供的代码没有后端,程序跑不起来。不过还好,有代码参考也不错。
这里我不得不吐槽一下网上有的文章,太TMD坑,甚至还有故意留坑让你自己去排查的,心中简直就是万马奔腾的赶脚~
设计思路
- 通过改造获取用户信息接口,有用户信息接口提供用户信息和菜单权限,并将菜单权限存到本地(user.js文件改造)
- 改造本地路由(router.js文件改造)
- 添加菜单解析方法(util.js添加方法)
就这么简单,只需要这三步就行了,不知道网上的怎本写的那么复杂。
开始改造
-
1、将获取到的菜单存到本地缓存(user.js改造),用户登录成功后将菜单存到本地
-
引入localSave方法
-
将数据存到本缓存(这个数据是由后端返回的,你可以先直接写个死数据在这)
如果你还没开始对接后端的话,那就直接考下面代码替换黄色的部分即可
var menus = [ {
path: '',
name: 'doc',
meta: {
access: ['超级管理员'],
title: '文档',
href: 'https://lison16.github.io/iview-admin-doc/#/',
icon: 'ios-book'
}
},
{
path: '/join',
name: 'join',
component: 'components/main',//注意,这一步很重要Main必须这样替换掉
children: [
{
path: 'join_page',
name: 'join_page',
meta: {
icon: '_qq',
title: 'QQ群'
},
component: 'view/join-page.vue'
}
]
}];
//将菜单存到本地
localSave('userRouters',JSON.stringify(menus))
-
2、router.js改造
- 1、引入localRead和backendMenusToRouters 方法
-
2、原来的js进行拆分,拆分成系统菜单和业务菜单,比如404、401、500、登录之类的菜单就不需要放进行数据库,直接放这本地就行了
- sysRoutes存是本地菜单
//后端返回的用户菜单
export const userRoutes = () => {
//从本地缓存中拿取菜单
var jsonRouters = localRead('userRouters');
//将本地json数据转成json对象后,再通过backendMenusToRouters方法处理component
return jsonRouters ? backendMenusToRouters(JSON.parse(jsonRouters)) : []
}
export default [ ...userRoutes(), ...sysRoutes];
-
2、util.js改造
- 1、添加下面这段代码拷进去就行了
//#region 动态路由处理
/**
* @description 将后端菜单树转换为路由树
* @param {Array} menus
* @returns {Array}
*/
export const backendMenusToRouters = (menus) => {
let routers = []
forEach(menus, (menu) => {
// 将后端数据转换成路由数据
let route = backendMenuToRoute(menu)
// 如果后端数据有下级,则递归处理下级
if (menu.children && menu.children.length !== 0) {
route.children = backendMenusToRouters(menu.children)
}
routers.push(route)
})
return routers
}
/**
* @description 将后端菜单转换为路由
* @param {Object} menu
* @returns {Object}
*/
const backendMenuToRoute = (menu) => {
// 原先routers写法是component: () => import('@/view/error-page/404.vue')
let route = Object.assign({}, menu)
if(route.component)
route.component = () => import(`@/${menu.component}`)
return route
}
//#endregion
#到这里需要用到的代码就贴完了
注意!注意!注意!:这个很重要,一定要看!
原始前端代码:
component: () => import('@/view/join-page.vue')
component: Main,
改造后(数据库里只能存下面这种代码):
component: 'view/join-page.vue'
component: 'components/main',
我遇到的最大困难就是不知道怎么将后端代码转成前端对象,不然我都不用到网上去翻代码了,哎,怪自己js功底不够扎实啊~
“component:Main”必须存全路径“component: ‘components/main’”。或者存成“component: ‘Main’”,注意Main是用单引号引起来的哦!
我参考的这篇文章的代码是针对Main、parentView做单独处理,而且必须要引入(import)相应的文件。我觉得这样不好,如果要使用其他公共的文件就得改代码,所以我直接使用全路径(components/main)。
外部代码参考
import Main from '@/components/main' // Main 是架构组件,不在后台返回,在文件里单独引入
import parentView from '@/components/parent-view' // 获取组件的方法
// @函数: 遍历后台传来的路由字符串,转换为组件对象
export const filterAsyncRouter = asyncRouterMap => {
const accessedRouters = asyncRouterMap.filter(route => {
if (route.component) {
if (route.component === 'Main') {
// Main组件特殊处理
route.component = Main
} else if (route.component === 'parentView') {
// parentView组件特殊处理
route.component = parentView
} else {
// route.component = _import(route.component)
route.component = lazyLoadingCop(route.component)
}
}
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children)
}
return true
})
return accessedRouters
}
其他唠嗑
不赶时间的话可以继续看下》》》
原本我是想把菜单存到user的state中的,但是有几个问题,
1、刷新后state数据会丢失
2、state和菜单不是双向绑定的,由于存进去是异步的,数据还没开始存菜单就已经加载出来,等数据存进去后菜单也不能自动加载出来。这里的问题就是:存进去后我不知道应该怎么通知菜单重新将新增加载新菜单。
3、这里还有个问题就是菜单是由用户信息接口返回过来的,可以单独做一个接口来获取用户菜单。主要是这个项目不是高并发的业务量也不大,为了节省时间就把他简化了
发现BUG了
登录后没有菜单,必须刷新后才显示
-
我做了以下整改
-
- 将菜单存储改成登录成功后存储到本地(跟这个BUG没关系,只是这样可以减少接口调用)
-
- 添加下面两行代码
- 添加下面两行代码
-
- app.js修改这3个地方
- app.js修改这3个地方
FK还是有BUG
菜单是正常显示出来了,但是点了菜单后提示401(无权限)错误
不想搞了,来个终极的,登录成功后不用路由跳转,用href来跳转,搞定!