废话不多说直接上代码:
首先一般的后台管理都是有登录页面的 我们在登陆页面实现 具体的 接口调用 获取 动态菜单和权限
这里我们就简单mock一下 上代码:
vue3.x-admin\src\mock\menu.json
[
{
"path": "/home",
"meta": { "title":"首页", "icon":"house", "isHideSubMenu": true, "isAuth": true },
"component" : "components/layout/Template.vue",
"children" : [
{
"path": "",
"meta": { "title":"首页" },
"component" : "views/home/Index.vue"
}
]
},
{
"path": "/article",
"redirect": "/article/list",
"meta": { "title":"文章管理", "icon":"document", "isAuth": true },
"auths": [ "article_add", "article_view", "article_delete", "article_edit" ],
"component" : "components/layout/Template.vue",
"children" : [
{
"path": "list",
"meta": { "title":"文章管理" },
"component" : "views/article/List.vue"
},
{
"path": "add",
"meta": { "isHide": true, "title":"新增文章" },
"component" : "views/article/Add.vue"
}
]
}
]
这是模拟的mock 菜单数据 我们在 登陆成功后 开始初始化 菜单
vue3.x-admin\src\views\login\Index.vue
登陆
这里我们就把菜单缓存到了store当中了,
这时候我们的动态路由在 路由守卫 beforeEach 中实现,其中有几点需要注意,有些坑 坑了我挺长时间的:
这些都是问题 我研究了半天 可能也是文档没看太明白!!!不多说了 上代码
vue3.x-admin\src\router\index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import CookieUtil from 'cookie-tool-plug'
import store from '@/store'
import _ from 'lodash'
const routes = [
// 主模板
{
path: '',
name: 'app',
meta: {},
component: () => import('@/views/Main.vue'),
children: [
{
path: '/no-auth',
meta: { title:'暂无权限', isHide: true },
component: () => import('@/views/404/noAuth.vue'),
},
{
path: '/404',
name: '404',
meta: { title:'404', isHide: true },
component: () => import('@/views/404/404.vue'),
},
]
},
{
path: '/login',
name: 'login',
component: () => import('@/views/login/Index.vue'),
},
{
path: '/:pathMatch(.*)*',
redirect: '/404'
}
];
const router = createRouter({
history: createWebHashHistory(),
routes,
})
// 权限检查
const asyncGetAuthFun = to => {
return new Promise((resolve, reject) => {
if(!CookieUtil.get('token') && to.path !== '/login'){
resolve(false)
} else {
resolve(true)
}
})
}
// 动态路由
const hasNecessaryRoute = () => {
return router.getRoutes().find(v=>v.path === '')['children'].length !== 2
}
// 生产路由
// const _import = file => require('@/' + file).default
const generateRoute = () => {
const menus = _.cloneDeep(store.state.global.menus)
// 获取组件的方法
const getMenus = (menus) => {
menus.forEach(item=>{
item.component = import('@/' + item.component)
if(item.children) {
getMenus(item.children)
}
})
}
getMenus(menus)
router.addRoute({path: '', meta: {}, redirect:menus[0]['path'], component: () => import('@/views/Main.vue'), name: 'app' , children: [ ...menus, ...routes[0]['children'] ]})
}
router.beforeEach(async (to, from) => {
try {
const res = await asyncGetAuthFun(to)
if(!res) {
return '/login'
} else if(to.path !== '/login' && !hasNecessaryRoute()) {
generateRoute()
if(to.redirectedFrom){
return to.redirectedFrom.fullPath
} else {
return to.fullPath
}
} else {
return true
}
} catch (error) {
if (error instanceof NotAllowedError) {
return false
} else {
throw error
}
}
})
export { router, routes }
这个地方实现了 路由拦截, 登陆权限验证, 动态添加路由 以及默认导航 页面实现
可以看到我们 使用 item.component = import('@/' + item.component)
这个来动态拼接 实现了 把字符串转换成了 实际模板,前面好像必须@/ 这个我也没细细研究,有老铁知道可以评论。
我们让动态路由只添加一次的 判断条件是 hasNecessaryRoute
这个函数 主要是根据 默认子路由数量来的 因为默认静态路由 是有两条的 如果超过两条 就代表已经添加过了。
同时我们是怎么实现 刷新重新跳转到 原来的页面的 因为刷新 默认会重定向到404 我们根据
return to.redirectedFrom.fullPath
这个来判断是否重定向 在没有动态添加的判断里面 如果有 那么添加完 动态路由就跳转回去
vue-router4.x 的路由守卫 有点饶人 建议多看几遍 不然你一不小心就陷入死循环当中了 , 嘎嘎嘎嘎
最后成功实现了 具体 面包屑 还有左侧菜单生成 可以看下仓库。就不贴了 比较麻烦!!!
vue3.x-admin
博客:夏日里的一把阳光 – 全栈开发程序员 可以画原型,前端开发,后端开发 记录生活点点滴滴 负重前行,努力生活