vue中动态路由实现

5/17/2021 vue

# 前言

  • 路由版本 ,router.3x
"vue-router": "^3.5.2",
1

# 代码已经上传到github

代码地址 (opens new window) 有用求个star

# 流程

1、用户登陆,获取后端返回的路由 2、使用router.addRoute动态添加到路由 文档 (opens new window) 3、使用router.getRoutes读取路由 文档 (opens new window) 4、注销的时候,把路由重置到登陆前的数据。

# 注意点

  • 路由版本:"vue-router": "^3.2.0",

  • 官方已经废弃了addRoutes

  • 目前应该使用addRoute!!!

  • 获取路由函数router.getRoutes()返回的数组不会有层级,会把子路由提到最外面一层。

# 核心代码介绍

//模拟后端传的路由
export const authRouter = [
{
path: '/allSeePage',
name: '所有人可见',
component: 'allSeePage' //后面我们使用require([`@/views/${view}`], resolve) 进行动态加载
},
{
path: '/adminPage',
name: '管理员可见',
component: 'adminPage'
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13

我把登陆注销添加路由、方法都放在vuex内了

# 1、state

state: {
userInfo: {
userName: '',
password: '',
token: '',
routerList: [] //存放后端返回的路由列表
}
},
1
2
3
4
5
6
7
8

# 2、vuex内添加路由方法 ADD_ROUTE

vuex-mutaions

mutations: {
ADD_ROUTE(state) {
let routerList = JSON.parse(JSON.stringify(state.userInfo.routerList))
console.log(26, router.getRoutes().length)
//路由未添加之前是4个,添加完之后是6个,我们用是否小于6个,来判断是否要添加
if (router.getRoutes().length < 6) {
routerList = filterAsyncRouter(routerList)//路由动态添加
console.log('路由添加前', router.getRoutes())
routerList.forEach((i) => {
//在home父路由内添加子路由
router.addRoute('home', i)
})
console.log('路由添加后', router.getRoutes())
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2、登陆

主要就是读取登陆接口路由,然后把路由添加进去

  • vuex
state: {
userInfo: {
userName: '',
password: '',
token: '',
routerList: [],//当前登陆用户的路由列表-由后端传过来
}
},
mutations: {
SET_USER_INFO(state, val) {
state.userInfo = Object.assign(state.userInfo, val)
}
},
actions: {
//登陆
login({ commit }, userInfo) {
const { userName, password } = userInfo
return new Promise((resolve) => {
//模拟登陆,获取用户信息, 权限路由列表
//假设返回的有token, 路由列表(根据不同用户返回不同)
/**********************模拟后端传过来的路由列表----S***********************/
let routerList = []
if (userName === 'admin') {
routerList = authRouter
} else if (userName === 'commonUser') {
routerList = [authRouter[0]]
}
/**********************模拟后端传过来的路由列表----E***********************/
let token = 'testToken'
//把用户信息存入vuex
commit('SET_USER_INFO', {
userName,
password,
token,
routerList
})
//添加路由
commit('ADD_ROUTE')
resolve()
})
},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 3、注销-重置路由

vuex-actions

actions:{
//注销
logout({ commit, state }) {
return new Promise((resolve) => {
console.log(state.userInfo.token, '注销了')
commit('SET_USER_INFO', {
userName: '',
password: '',
token: ''
})
//重置路由
resetRouter() //这是路由里面的重置方法,引入的
resolve()
})
},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 4、渲染菜单

利用router.getRoutes(),获取已经添加的路由,此方法会把所有层级变为一层,子路由会有parent属性 最后渲染到页面上 在左侧导航组件内

let routeList = this.$router.getRoutes()
//查找home路由的子路由,然后渲染出来
this.menuList = routeList.filter(
(i) => i.parent && i.parent.name === 'home'
)
1
2
3
4
5
  • 重置路由方法 permission.js
//路由的创建
const createRouter = () =>
new VueRouter({
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
//重置路由
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}

export const router = createRouter()

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 路由钩子函数beforeEach

流程

代码

router.beforeEach(async (to, from, next) => {
//获取用户信息
let { userInfo } = store.state
const { userName } = userInfo
console.log('用户角色', userName ? userName : '未登陆')
//有用户信息
if (userName) {
await store.dispatch('addRoute')
let { routerList } = userInfo
//根据to.name来判断是否为动态路由, 是否有人知道还有更好的判断方法?
if (!to.name) {
//当前路由是动态的,确定是有的, 有就跳自己,没有就跳404
if (routerList.findIndex((i) => i.path === to.path) !== -1) {
next({ ...to, replace: true })
} else {
next('/404')
}
} else {
next()
}
}
//无用户信息
else {
//没有权限访问,跳入没有权限页面/或者登陆页面
// 跳转之前要判断一下是否为需要跳转的界面,不然会进入死循环
if (to.path === '/login') {
next()
} else {
Message.error('请先登陆!')
next('/login')
}
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 路由动态component引入

export const loadView = (view) => {
// 路由懒加载
return (resolve) => require([`@/views/${view}`], resolve)
}
1
2
3
4

# 遇到的坑

1、在vue-route:3x版本内,废弃了router.addRoutes,而是使用router.addRoute,注意没有s 2、router.getRoutes获取的路由层级只有一层!不会出现子路由,子路由会有parent属性。 3、永远不要使用this.$router.options.routes来获取路由,因为动态修改路由这里面不会变化,真的是坑啊!! 4、路由f5刷新后,之前动态添加的路由都会丢失。。 5、404页面,钩子函数内进行判断就好。 不要写这句 { path: '*', redirect: '/404' }

可以参考花裤衩大佬的提问 (opens new window)

# 写在最后

Last Updated: 3/28/2025, 11:10:43 AM