一般来说,[前端项目]
中的路由,很有可能是需要动态注册的。因为菜单可能在管理系统中维护,还跟权限绑定,用户登录以后,需要动态展示菜单。菜单往往跟路由挂钩,因此,路由需要动态注册
那么就分为前端默认路由 和 后端接口动态路由
1.前端默认路由 可以存放一些 登录页面 404 等公共页面
2.后端接口动态路由,就是根据用户的权限展示那些页面,由接口决定,在通过 router.addRoute
进行添加
- 在前端项目中 router 文件夹下面创建 index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Main from '@/views/Main'
import Role1 from '@/views/role/role1'
import store from '@/store'
Vue.use(VueRouter)
// 静态路由
export const constantRoutes = [
{
path: '/login',
name: 'login',
component: () =>
import( "@/views/LoginPage"),
meta: {
keepAlive: true,
isTab: false,
isAuth: false,
},
},
{
path: '/',
component: Main,
name: 'Main',
redirect: '/home',
children: [
]
},
{
path: '/404',
name: '404',
component: () =>
import('@/views/error/404'),
hidden: true
},
{
path: '/401',
name: '401',
component: () =>
import( '@/views/error/401'),
hidden: true
},
// {
// path: "*",
// redirect: "/404",
// },
]
const router = new VueRouter({
mode: 'hash',
scrollBehavior: () => ({ y: 0 }),
routes:constantRoutes
})
// 解决ElementUI报重复点击菜单错误
const originalPush = router.push
router.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
export default router
这里需要注意一下
- 我把获取用户信息的接口放入到了 vuex
import { login, logout, getInfo } from '@/api/login'
import { getStore, setStore, clearStore, removeStore } from '@/util/storage'
import { deepClone } from '@/util/validate'
import router from '@/router';
// 动态菜单 多层嵌套
const generateRoutes = (menuList, parentPath = '') => {
return menuList.map(menuItem => {
const fullPath = parentPath + menuItem.menuPath;
const route = {
path: fullPath,
component: () => import(`@/views/${menuItem.menuComponentPath}`),
name: menuItem.menuName,
meta: { title: menuItem.menuTitle, noCache: true, icon: menuItem.menuIconName },
id: menuItem.id
};
if (menuItem.children && menuItem.children.length > 0) {
route.children = generateRoutes(menuItem.children, fullPath + '/');
}
router.addRoute("Main",route);
return route;
});
};
// 扁平化动态路由
const flattening=(menuTree)=>{
console.log(menuTree,'menuTree');
let tempArray =[]
menuTree.forEach(ele=>{
tempArray.push(ele)
// 递归处理
if (ele.children) {
tempArray.push(...flattening(ele.children));
}
})
return tempArray
}
const user = {
state: {
meun:getStore({
name: 'menu'
}) || [],
},
mutations: {
SET_MENU(state, menu) {
state.menu = menu
setStore({
name: 'menu',
content: menu,
type: 'session'
})
},
},
actions: {
// 获取用户信息
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo().then(res => {
console.log(res.data, 'GetInfo');
const menu = deepClone(res.data.menus);
const menus = generateRoutes(menu); // 生成动态菜单
const roles = flattening(menus)
console.log(menus,roles,'routes');
commit('SET_MENU', menus)
resolve(res)
}).catch(error => {
reject(error)
})
})
},
}
}
export default user
- 回到 view /login.vue 页面中 当登录成功之后 就调用这个接口
这个是后端给的接口
这个是登录成功之后 后端返回的数据
我们需要对这个数据进行处理 用于 侧边栏
头部导航
还有动态路由
的配置
因为后端给到的数据不是路由表里面 一一对应的 path name 等键值对的形式,就需要自行处理
[
{
"path": "/home",
"name": "Home",
"meta": {
"title": "首页",
"noCache": true
},
"id": 1
},
{
"path": "/n1",
"name": "Nested1",
"meta": {
"title": "Nested1",
"noCache": true
},
"id": 3,
"children": [
{
"path": "/n1/n2",
"name": "Nested2",
"meta": {
"title": "Nested2",
"noCache": true
},
"id": 4
}
]
},
{
"path": "/test",
"name": "Test",
"meta": {
"title": "test",
"noCache": true
},
"id": 2
}
]
这个时候就存储一下,就可以直接使用了
我们在这里的时候就可以addRoute了,然后在页面中打印
注意
router.addRoute()
添加路由之后,通过router.options.routers
是查看不到添加的动态路由信息
需要使用router.getRoutes()
可以查看到
- 这个时候还没有完,会发现刷新这个就白屏了
正常
刷新
这里需要 去 路由守卫 router.beforeEach
里面去处理
/**
* 全站权限配置
*
*/
import router from '@/router'
import store from '@/store'
import Layout from '@/views/Main'
import { getStore, setStore, clearStore, removeStore } from '@/util/storage'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
NProgress.configure({ showSpinner: false })
/**
* 导航守卫,相关内容可以参考:
* https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
*/
// 记录路由
let hasRoles =true
router.beforeEach(async(to, from, next) => {
NProgress.start()
// 判断token
const token = getStore({ name: 'access_token' })
if (!token && to.name !== 'login') {
next({ name: 'login' })
NProgress.done()
} else if (token && to.name == 'login') {
// 跳转页面
next({ path: '/' })
NProgress.done()
} else {
if(token && hasRoles){
await store.dispatch("GetInfo")
hasRoles =false
next({...to,replace:true})
}else{
next()
}
NProgress.done()
}
})
router.afterEach(() => {
NProgress.done()
})
就不会出现白屏问题了,正常刷新正常有
关于 通配符 404页面,我的处理是在动态路由都添加进去之后在了添加
也是在 permission.js
中添加的
tip 可能遇到的问题
如果访问不成功,就需要关注,component 的引入,可能是自己的页面名称没有和它匹配
这里和我们在处理数据的时候,对于component 里面的路径有关的
好了,以上就是我的全部 实现过程,也走了很多弯路,尤其是那个router.options.routers
这个打印不出来我的动态路由,我一度迷茫,说addRoute 咋没有效果 失效了呢,惆怅是不是添加进入的时机不对,救命!!!