手摸手教你实现vue的动态路由(router.v4.x版本)
前言
- 路由版本 ,
router.4x
"vue-router": "^4.0.0-0",
- 需要看
router.3x
的请看这里手摸手教你实现vue的动态路由(router.v3.x版本) - 源代码地址 vue3-dynamic-router,
router4
基本和vue3
绑定的, 所以此demo
是用vue3
语法写的。
动态路由用到的router4
的api
1、 获取路由列表 getRoutes()
2、 添加路由 addRoute(name)
为某个路由添加单个路由, 注意不是addRoutes(), 已废弃!!!
。
3、 删除路由 removeRoute(name)
删除某个路由,注销的时候删除添加的路由。
整体流程
1、用户登陆,获取后端返回的路由, 存入vuex
2、使用router.addRoute
动态添加到路由
3、使用router.getRoutes
读取路由
4、注销的时候,removeRoute
删除添加的路由
实现效果
不同用户登陆显示不同侧边路由导航
核心代码介绍
1、模拟的动态路由列表
//模拟后端传过来的路由
export const authRouter = [
{
path: "/allSeePage",
name: "所有人可见",
component: "allSeePage",
meta: {
isSideBar: 1
}
},
{
path: "/adminPage",
name: "管理员可见",
component: "adminPage",
meta: {
isSideBar: 1
}
}
]
2、登陆添加路由
- 登陆事件
const onSubmit = () => {
//触发登陆,保存信息,添加路由
store.dispatch("login", userInfo.value).then(() => {
console.log("登陆跳转")
router.push({ path: "/home" })
})
}
vuex
-添加路由, 刷新后路由会消失, 我们要重新添加
ADD_ROUTE(state) {
console.log("路由添加前", router.getRoutes())
//路由未添加之前是3个,我们判断是否添加过,没添加过就添加
if (router.getRoutes().length === 3) {
let addRouterList = filterAsyncRouter(
JSON.parse(JSON.stringify(state.userInfo.routerList)) //这里深拷贝下,不然会出问题
)
addRouterList.forEach((i) => {
console.log("添加路由", i)
router.addRoute("home", i)
})
}
console.log("路由添加后", router.getRoutes())
}
3、渲染菜单
利用
router.getRoutes()
,获取已经添加的路由,此方法会把所有层级变为一层注意:这里获取到的route对象与router3.x的版本不一样,route没有parent属性了, 通过meta来判断是否是菜单
const routerList = router.getRoutes() //这里获取到的route对象与router3.x的版本不一样,需要注意下
menuList.value = routerList.filter((route) => {
const isSidebar = route.meta.isSideBar ? route.meta.isSideBar : 0
if (isSidebar) {
return route
}
})
4、 vuex
注销-删除路由
//注销
logout({ commit, state }) {
return new Promise((resolve) => {
console.log(state.userInfo.token, "注销了")
//拷贝一下
const delRouterList = JSON.parse(
JSON.stringify(state.userInfo.routerList)
)
//删除添加的路由,如果路由是多层的 递归下。。
delRouterList.forEach((route) => {
router.removeRoute(route.name)
})
//删除路由,清空用户信息
commit("SET_USER_INFO", {
userName: "",
password: "",
token: "",
routerList: []
})
resolve("注销 success, 清空路由,用户信息")
})
}
路由钩子函数beforeEach
- 刷新后触发vuex的添加路由
- 代码
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,, tip: 刷新后动态路由的to.name为空
if (routerList.findIndex((i) => i.path === to.path) !== -1) {
next({ ...to, replace: true })
} else {
next("/404")
}
} else {
console.log(28, router.getRoutes())
next()
}
}
//无用户信息
else {
//没有权限访问,跳入没有权限页面/或者登陆页面
// 跳转之前要判断一下是否为需要跳转的界面,不然会进入死循环
if (to.path === "/login") {
next()
} else {
ElMessage.error("请先登陆!")
next("/login")
}
}
})
路由组件动态component
引入
filterAsyncRouter
路由懒加载导入, 路由的component
与前端文件路径绑定,支持多层嵌套- 注意 这里引入与
router3
不一样已经备注。
export const loadView = (view) => {
// 路由懒加载
//return (resolve) => require([`@/views/${view}`], resolve) router3版本
return () => Promise.resolve(require(`@/views/${view}`).default) //router4版本
}
//为权限路由异步添加组件
export const filterAsyncRouter = (routeList) => {
return routeList.filter((route) => {
console.log(9, route)
if (route.component) {
// 如果不是布局组件就只能是页面的引用了
// 利用懒加载函数将实际页面赋值给它
route.component = loadView(route.component)
// 判断是否存在子路由,并递归调用自己
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children)
}
return true
}
})
}
遇到的坑
1、router.getRoutes
获取的路由层级只有一层!。4.0的路由版本已经有children属性了。
2、永远不要使用router.options.routes
来获取路由,因为动态修改路由这里面不会变化。
3、路由f5刷新后,之前动态添加的路由都会丢失。。 需要重新添加
4、404页面,钩子函数内进行判断就好。 不要写这句 { path: '*', redirect: '/404' }
写在最后
- 代码内可能有Bug,希望可以在仓库issues提出。
- 在
beforeEach
判断是否为动态路由那是否有更好的解决方式? - 代码地址-vue3-dynamic-router
- 感谢阅读✿
转载自:https://juejin.cn/post/7043988643941203975