vue3+vue-router+vite實(shí)現(xiàn)動(dòng)態(tài)路由的全過程
什么是動(dòng)態(tài)路由
什么場景會(huì)用到動(dòng)態(tài)路由
舉一個(gè)最常見的例子,比如說我們要開發(fā)一個(gè)后臺(tái)管理系統(tǒng),一般來說后臺(tái)管理系統(tǒng)都會(huì)分角色登錄,這個(gè)時(shí)候也就涉及到了權(quán)限,比如說這個(gè)后臺(tái)管理系統(tǒng)現(xiàn)在有超級管理員,管理員,運(yùn)維,財(cái)務(wù)等這幾個(gè)角色,每個(gè)角色登錄系統(tǒng)之后都會(huì)有不同的權(quán)限,超級管理員需要所有的權(quán)限,財(cái)務(wù)可能只需要財(cái)務(wù)相關(guān)的模塊(菜單)以及按鈕等,通常實(shí)現(xiàn)這種需求會(huì)有以下常見方案
路由表由前端去維護(hù)
也就是說我們已知這幾個(gè)角色分別對應(yīng)哪些權(quán)限,前端寫好路由配置表,,后端只需要告訴你當(dāng)前登錄人是屬于哪個(gè)角色,前端根據(jù)角色類型去寫一個(gè)過濾函數(shù),獲取該角色所擁有的菜單以及按鈕,然后動(dòng)態(tài)的去添加路由,這樣做有一個(gè)缺點(diǎn)就是,如果又增加了一個(gè)新的角色怎么辦?某個(gè)角色想增加一些權(quán)限怎么辦?這個(gè)時(shí)候前端就需要去新增或者修改代碼,一點(diǎn)也不友好
路由表的數(shù)據(jù)由后端返回
這種也是常用的一種方式,可能我們的系統(tǒng)里面需要開發(fā)一些功能,如菜單管理
,角色管理
,用戶管理
等,也就是常說的權(quán)限中心,前端開發(fā)完的頁面所對應(yīng)的路由信息有后端去維護(hù),這個(gè)時(shí)候我們在開發(fā)的時(shí)候需要約束某一種規(guī)則,比如所有頁面都放到/src/views
目標(biāo)下面,然后通過菜單管理去維護(hù)數(shù)據(jù),維護(hù)完的數(shù)據(jù)可以到角色管理里面去配置角色菜單,配置完角色,可以到用戶管理里面給某個(gè)用戶配置角色等一些列流程,這樣的話即使新增一個(gè)角色,或者修改一個(gè)角色的角色菜單,前端都不需要去修改代碼,只要在菜單管理里面維護(hù)好了數(shù)據(jù),想怎么改怎么改,后端返回的數(shù)據(jù)格式可能如下:
[ { path: "/application", name: "application", component: "Layout", title: "應(yīng)用管理", show: true, icon: "", children: [ { path: "", name: "application-index", component: "/application/index.vue", }, ], }, { path: "/permission", name: "permission", component: "Layout", title: "權(quán)限管理", show: true, icon: "", children: [ { path: "menu", name: "permission-menu", component: "/permission/menu/index.vue", title: "菜單管理", show: true, icon: "", }, { path: "user", name: "permission-user", component: "/permission/user/index.vue", title: "用戶管理", show: true, icon: "", }, { path: "role", name: "permission-role", component: "/permission/role/index.vue", title: "角色管理", show: true, icon: "", }, ], }, ]
其實(shí)仔細(xì)觀察這個(gè)數(shù)據(jù)結(jié)構(gòu),是不是有點(diǎn)熟悉,path
,name
,component
,children
,我們好像手動(dòng)維護(hù)路由表的時(shí)候也會(huì)用到這些屬性
如何實(shí)現(xiàn)動(dòng)態(tài)路由
實(shí)現(xiàn)動(dòng)態(tài)路由其實(shí)就要用到vue-router
提供的一個(gè)方法,叫addRoute
在之前版本的時(shí)候是addRoutes
,現(xiàn)在非版本的vue-router
給廢除了addRoute()
如何使用呢?可以看一下官方文檔
當(dāng)我們添加一個(gè)主路由
的時(shí)候
router.addRoute({ path: '/permission', name: 'permission', component: () => import('xxxxx')})
添加子路由
也就是嵌套路由
router.addRoute('主路由的name', { path: 'settings', component: AdminSettings })
既然我們已經(jīng)知道了addRoute()
方法如何使用,下面我們就可以去實(shí)現(xiàn)這部分邏輯
我們看一下官方文檔的導(dǎo)航守衛(wèi)里面的內(nèi)容
在之前我們使用導(dǎo)航守衛(wèi)的時(shí)候需要一個(gè)參數(shù)next()
去控制是否放行以及去哪個(gè)頁面,但是在新版本的vue-router
里面可以不是用next()
,當(dāng)然你是用也行~
我們可以新建一個(gè)permission.ts
文件
import router from "./index"; import { useSessionStorage } from "@vueuse/core"; import { StorageEnum } from "@/enum"; import { useUserStore } from "@/store"; const whiteList = ["/login", "/404"]; router.beforeEach(async (to) => { const token = useSessionStorage(StorageEnum.TOKEN, "").value; // 如果在白名單里面 并且 token 不存在 if (whiteList.includes(to.path) && !token) { return true; } else { const { menuList, getMenuList } = useUserStore(); // 如果為空數(shù)組,name就請求接口重新獲取后端維護(hù)的路由數(shù)據(jù) if (!menuList.length) { await getMenuList(); console.log("獲取全部路由 =>", router.getRoutes()); // 觸發(fā)重定向 不這樣寫會(huì)導(dǎo)致刷新找不到路由 兩種寫法都行 // return { path: to.fullPath }; return to.fullPath; } } });
這里我們可以看到一會(huì)return true
一會(huì)return to.fullpath
是為什么,通過官方導(dǎo)航守衛(wèi)
里面的介紹,我們可以知道的是
通過官方文檔動(dòng)態(tài)路由
,我們可以直到
所以說return to.fullpath
是官方告訴我們要這么使用,也是為了解決動(dòng)態(tài)路由
頁面刷新的時(shí)候會(huì)出現(xiàn)頁面空白
或者404
的問題
出現(xiàn)404的話比如說你在路由表中維護(hù)了下面路由映射
{ path: "/:pathMatch(.*)", name: "page404", component: () => import("@/views/system/404.vue"), }
上面說的主要是在全局導(dǎo)航守衛(wèi)
里面的一些使用及注意事項(xiàng),我們可以看到并沒有用到addRoute()
這個(gè)方法,也沒有出現(xiàn)拿到后端數(shù)據(jù)前端轉(zhuǎn)換成路由表的相關(guān)代碼,但是我們可以看到有一個(gè)getMenuList()
函數(shù),我們在開發(fā)的時(shí)候,肯定是要考慮到復(fù)用以及復(fù)雜邏輯抽取的問題,一個(gè)動(dòng)態(tài)路由的實(shí)現(xiàn)會(huì)牽扯到很多知識(shí)點(diǎn)接口請求,vuex或者pinia狀態(tài)維護(hù),vue-router,vite里面怎么獲取文件等
下面看一下如何獲取到接口給的數(shù)據(jù),轉(zhuǎn)換成vue-router能夠識(shí)別的數(shù)據(jù)
首先我們要看一個(gè)vite官方給提供的功能,我們拿到后端給的文件路徑
如上面代碼出現(xiàn)的component
字段,如/application/index.vue
,這個(gè)文件可能在我們本地項(xiàng)目中的src/views/application/index.vue
這個(gè)路徑下
我們需要把它轉(zhuǎn)換成一個(gè)下面的格式() => import('xxxx')
,我們需要?jiǎng)討B(tài)的去拼接獲取文件,該怎么實(shí)現(xiàn)呢?
vite官方文檔中有說明
需要使用import.meta.glob
,這個(gè)時(shí)候我們可以打印一下import.meta.glob("../views/**")
,看一下返回的到底是什么
返回的是一個(gè)對象,而對象的key
我們可以拼接獲取到,而value
正是我們想要的動(dòng)態(tài)獲取的文件路徑
以下代碼僅供參考,有很多需要完善的地方,只為演示使用
import type { RouterType } from "@/router/type"; import router from "@/router"; import type { RouteRecordRaw } from "vue-router"; export const useRouterConfig = () => { // 獲取views目錄下的所有的文件 不要使用@別名 const modules = import.meta.glob("../views/**"); const asyncRoutes = ref<RouterType[]>([]); const addRoutes = (menus: RouterType[]) => { asyncRoutes.value = menus; filterAsyncRouter(); // 動(dòng)態(tài)添加 / 路由 router.addRoute({ path: "/", redirect: asyncRoutes.value[0].path, }); }; const filterAsyncRouter = () => { const routerLoop = (routes: RouterType[], ParentName?: string) => { routes.forEach((item) => { if (item.component === "Layout") { item.component = () => import("@/layout/index.vue"); } else { item.component = resolveComponent(item.component); } const { title, show, icon, name, path, component, children } = item; const route: RouteRecordRaw = { component, path, name, meta: { title, show, icon, }, children: children as any, }; // 動(dòng)態(tài)添加路由 if (ParentName) { router.addRoute(ParentName, route); } else { router.addRoute(route); } if (item.children && item.children.length > 0) { routerLoop(item.children, item.name); } }); }; routerLoop(asyncRoutes.value); }; const resolveComponent = (path: string) => { console.log(modules); // 拿到views下面的所有文件之后,動(dòng)態(tài)拼接`key`去獲取value const importPage = modules[`../views${path}`]; if (!importPage) { throw new Error( `Unknown page ${path}. Is it located under Pages with a .vue extension?` ); } return importPage; }; return { addRoutes }; };
綜上所述:
要想實(shí)現(xiàn)vite+vue-router實(shí)現(xiàn)動(dòng)態(tài)路由我們需要用到
addRoute()
import.meta.glob()
獲取后端tree數(shù)據(jù),遞歸循環(huán),可能業(yè)務(wù)會(huì)有type類型,比如分為模塊,菜單,頁面,按鈕等,到時(shí)候結(jié)合業(yè)務(wù)去實(shí)現(xiàn)邏輯
導(dǎo)航守衛(wèi)使用時(shí)的注意事項(xiàng),否則會(huì)出現(xiàn)刷新白屏,或者路由訪問死循環(huán)等
總結(jié)
到此這篇關(guān)于vue3+vue-router+vite實(shí)現(xiàn)動(dòng)態(tài)路由的文章就介紹到這了,更多相關(guān)vue-router+vite動(dòng)態(tài)路由內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue2項(xiàng)目導(dǎo)出操作實(shí)現(xiàn)方法(后端接口導(dǎo)出、前端直接做導(dǎo)出)
這篇文章主要給大家介紹了關(guān)于vue2項(xiàng)目導(dǎo)出操作實(shí)現(xiàn)方法的相關(guān)資料,文中介紹的是后端接口導(dǎo)出、前端直接做導(dǎo)出,通過代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-05-05vue 實(shí)現(xiàn)LED數(shù)字時(shí)鐘效果(開箱即用)
這篇文章主要介紹了vue 實(shí)現(xiàn)LED數(shù)字時(shí)鐘效果(開箱即用),每一個(gè)數(shù)字由七個(gè)元素構(gòu)成,即每一個(gè)segment元素,本文給大家分享實(shí)現(xiàn)實(shí)例,感興趣的朋友一起看看吧2019-12-12vue導(dǎo)入excel文件,vue導(dǎo)入多個(gè)sheets的方式
這篇文章主要介紹了vue導(dǎo)入excel文件,vue導(dǎo)入多個(gè)sheets的方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08vue中formdata傳值給后臺(tái)時(shí)參數(shù)為空的問題
這篇文章主要介紹了vue中formdata傳值給后臺(tái)時(shí)參數(shù)為空的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06vue使用WEB自帶TTS實(shí)現(xiàn)語音文字互轉(zhuǎn)的操作方法
這篇文章主要介紹了vue使用WEB自帶TTS實(shí)現(xiàn)語音文字互轉(zhuǎn),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01