Vue3中簡單實現(xiàn)動態(tài)添加路由
前言
通過后端接口的返回值,動態(tài)添加路由,是作為權(quán)限控制的一種常見方式,本文將簡單講解如何在Vue3中動態(tài)添加路由。
示例數(shù)據(jù)
[
{
"id": 1,
"pid": 0,
"url": "/dashboard",
"title": "控制面板板",
"component": "/src/views/dashboard/DashboardView.vue",
"icon": "SlidersOutlined",
"is_show": 0,
"level": 1,
"sort": 1,
"order": "1",
"type": "menu",
"status": 0,
"children": null
},
{
"id": 2,
"pid": 0,
"url": "/system",
"title": "系統(tǒng)設(shè)置",
"component": null,
"icon": "ToolOutlined",
"is_show": 0,
"level": 1,
"sort": 7,
"order": "2",
"type": "menu_dir",
"tips": null,
"status": 0,
"children": [
{
"id": 7,
"pid": 2,
"url": "/system/menu",
"title": "菜單管理",
"component": "/src/views/system/MenuView.vue",
"icon": "BarsOutlined",
"is_show": 0,
"level": 2,
"sort": 3,
"order": "2,7",
"type": "menu",
"tips": null,
"status": 0,
"children": [
{
"id": 8,
"pid": 7,
"url": "/system/menu/add",
"title": "新增菜單",
"component": null,
"icon": null,
"is_show": 1,
"level": 3,
"sort": 1,
"order": "2,7,8",
"type": "button",
"tips": null,
"status": 0,
"children": null
}
]
}
]
},
]思路分析
動態(tài)添加路由的實質(zhì),就是先將后端返回的json數(shù)據(jù)轉(zhuǎn)化成一個個RouteRecordRaw形式的對象,然后調(diào)用Vue Router的addRoute方法,添加進路由列表中。由于每個路由地址都會對應(yīng)一個Vue組件,因此還需要將Vue組件都通過import.meta.glob讀取到內(nèi)存中。
具體實現(xiàn)函數(shù)
const viewsComponent: Record<string, any> = import.meta.glob("/src/views/**/*.vue", { eager: true })
const addRouteAll = (menu: RoleMenu[]) => { //RoleMenu就是接口返回的數(shù)據(jù)的類型
menu.forEach(item => {
if (item.type === "menu" && viewsComponent[item.component]) {
addRouteItem(item)
}
if (item.children && item.children.length > 0) {
addRouteAll(item.children)
}
})
}
const addRouteItem = (route: RoleMenu) => {
const path = route.url
const component = viewsComponent[route.component]
const routeBaseInfo: RouteRecordRaw = {
path,
name: path.substring(1),
component: component.default,
meta: {
title: route.title,
icon: route.icon,
keepalive: route.children && route.children.length > 0 ? 0 : path.substring(1),
menu_type: "tab",
type: route.type,
url: route.url,
addTab: true
}
}
router.addRoute(routeBaseInfo)
}存在問題
路由何時處理?
筆者一開始認為,登錄成功后立刻調(diào)用獲取菜單的接口,然后處理路由,因此路由的處理應(yīng)該在登錄頁面中的登錄請求成功后進行處理,但是此時存在一個問題,用戶登錄成功進入后臺頁面,然后用戶刷新頁面,就會提示導航失敗,控制臺也會報錯,因此筆者認為應(yīng)該在登錄成功進入后臺頁面之后開始處理。
筆者后臺的主體頁面框架為MainLayout,因此筆者在此進行路由處理。
const getMenu = () => {
apiAuthMenuList().then(res => {
menuList.value = handleMenu(res.content) //菜單處理
addRouteAll(res.content)
})
}
onMounted(() => {
getMenu()
})導航失敗
?? [Vue Router warn] : No match found for location with path "/dashboard"
這是因為路由跳轉(zhuǎn)的時機要早于組件掛載,因此在組件掛載并處理路由前,路由就已經(jīng)跳轉(zhuǎn)并報錯了。
筆者解決這個問題的思路有兩個:
- 首先定義全局變量
routeReady,初始值為false,當路由處理完成后變?yōu)?code>true - 在路由守衛(wèi)
beforeEach中判斷,如果routeReady為false則處理路由,處理完成后跳轉(zhuǎn)。 - 創(chuàng)建一個Loading頁面,如果路由沒有匹配的地址則跳轉(zhuǎn)至Loading頁面,并在該頁面進行判斷:
- 如果
routeReady為true,說明去往的地址并不在該用戶的權(quán)限菜單中,轉(zhuǎn)向404頁面 - 如果
routeReady為false,則說明路由未加載完成,那么就在當前頁面等待,等routeReady為true時,再執(zhí)行上面的判斷
- 如果
筆者這里用了方法2。
//截獲所有未匹配的路由,進入Loading頁面
{
path: "/:pathMatch(.*)*",
component: () => import("../views/LoadingView.vue")
}//LoadingView.vue
watchEffect(() => {
if (globalStore.routeReady) {
const routeList = router.getRoutes()
if (routeList.find(i => i.path === router.currentRoute.value.fullPath)) {
router.push(router.currentRoute.value.fullPath)
} else {
router.push("/notFound")
}
}
})通過這種方式,可以在用戶刷新頁面后有一個順滑的體驗。
進入第一個路由
目前還存在一個問題,用戶在登錄跳轉(zhuǎn)后,會進入后臺頁面,但是此時不會進入到任一菜單中:

而我們希望登錄跳轉(zhuǎn)后能自動進入到第一個菜單,即:

因此我們需要一個方法來找到第一個可用的路由:
const getFirstRoute = (routes: RouteRecordRaw[]): false | RouteRecordRaw => {
const routerPaths: string[] = []
const routers = router.getRoutes()
routers.forEach(item => {
if (item.path) routerPaths.push(item.path)
})
let find: boolean | RouteRecordRaw = false
for (const key in routes) {
if (routes[key].meta?.type != "menu_dir" && routerPaths.indexOf(routes[key].path) !== -1) {
return routes[key]
} else if (routes[key].children && routes[key].children?.length) {
find = getFirstRoute(routes[key].children!)
if (find) return find
}
}
return find
}然后調(diào)用這個方法即可:
const init = () => {
const firstRoute = getFirstRoute(menuList.value!)
if (firstRoute) {
router.push(firstRoute.path)
}
}
onMounted(() => {
init()
})后記
到此這篇關(guān)于Vue3中簡單實現(xiàn)動態(tài)添加路由的文章就介紹到這了,更多相關(guān)Vue3動態(tài)添加路由內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Vue中延遲執(zhí)行某個函數(shù)的實現(xiàn)方式
在Vue中延遲執(zhí)行某個函數(shù),你可以使用setTimeout()函數(shù)或者Vue提供的生命周期鉤子函數(shù),本文通過一些示例代碼給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2023-12-12

