vue3實(shí)現(xiàn)動(dòng)態(tài)路由及菜單
一般來說,前端項(xiàng)目中的路由,很有可能是需要?jiǎng)討B(tài)注冊(cè)的。
因?yàn)椴藛慰赡茉诠芾硐到y(tǒng)中維護(hù),還跟權(quán)限綁定,用戶登錄以后,需要?jiǎng)討B(tài)展示菜單。
菜單往往跟路由掛鉤,因此,路由需要?jiǎng)討B(tài)注冊(cè)。
具體如何實(shí)現(xiàn)呢?
思路是,系統(tǒng)只提供默認(rèn)的路由,登錄以后,讀入菜單/路由數(shù)據(jù),加載。
這其中,可能會(huì)出現(xiàn)默認(rèn)路由與動(dòng)態(tài)路由有重疊的情況。
處理辦法是覆蓋。數(shù)據(jù)結(jié)構(gòu)方面,菜單與路由數(shù)據(jù)二合一。
一、項(xiàng)目結(jié)構(gòu)
這是我們一個(gè)項(xiàng)目的公共框架的代碼結(jié)構(gòu)。
我們打算在src/modules/存放具體業(yè)務(wù)系統(tǒng)的代碼,而外部是相對(duì)穩(wěn)定,可以復(fù)用的框架代碼。
二、默認(rèn)路由
src/router/default.js,內(nèi)容比較少,只有登錄、首頁、404三個(gè)。其余全都靠動(dòng)態(tài)注冊(cè)。
路由項(xiàng)中,自定義屬性放在meta里。動(dòng)態(tài)路由與默認(rèn)路由的數(shù)據(jù)結(jié)構(gòu)一致。
/** * 默認(rèn)路由 * 具體業(yè)務(wù)路由,應(yīng)在src/modules/router里定義,或者從后端動(dòng)態(tài)加載 */ export default [ /** * 路由項(xiàng)結(jié)構(gòu): *{ path: "/",//路徑,(必選;path、name、component是路由規(guī)定必選的元素) 也可以帶參數(shù),如 path: "/resource/detail/:id", name: "路由名稱,是路由唯一標(biāo)識(shí)",(必選) component: 指向組件,如 Home,或者() => import("../views/login/PageIndex.vue"),(必選) meta: {//meta里的屬性可以自定義,全部為可選項(xiàng) text: "名稱",//展示在菜單里,(可選) navi: true, //導(dǎo)航條(一級(jí)菜單),(可選) noLogin: true, //無須登錄即可瀏覽,(可選) access: "work:sysmanage,work:resourcemanage",//權(quán)限標(biāo)識(shí),(可選) }, children: [], }, */ { path: "/login", name: "login", component: () => import("../views/login/PageIndex.vue"), meta: { noLogin: true, //無須登錄即可瀏覽 }, }, { path: "/", name: "Home", component: () => import("../views/PageIndex.vue"), }, { path: "/notAllow", name: "notAllow", component: () => import("../views/sys/notAllow.vue"), }, ]; export const HomeName = "Home";
三、動(dòng)態(tài)注冊(cè)
注冊(cè)的時(shí)機(jī)是什么?在哪里注冊(cè)?怎么注冊(cè)?
答曰:登錄之后注冊(cè);在路由守衛(wèi)里注冊(cè);用router.addRoute()一個(gè)個(gè)加進(jìn)去。
1、登錄之后進(jìn)行注冊(cè),在路由衛(wèi)士里注冊(cè)
所謂路由守衛(wèi),就是路由規(guī)則。這名字我是從網(wǎng)上抄過來的。
src/router/index.js
import { createRouter, createWebHashHistory } from "vue-router"; import routes from "./default"; import routeAssembler from "./setup"; import { hasAuthority } from "@/utils/login.js"; const router = createRouter({ history: createWebHashHistory(), routes, }); // 路由守衛(wèi) let registerRouteFresh = true;//是否還沒有動(dòng)態(tài)加載過 router.beforeEach((to, from, next) => { const isLogin = localStorage.isLogin ? true : false; if (isLogin) { //已登錄情況下驗(yàn)證權(quán)限 let isAccess = hasAuthority(to.meta.access); if (!isAccess) {//沒有權(quán)限 next("/notAllow"); return; } if (registerRouteFresh) {//還沒有動(dòng)態(tài)加載過 //動(dòng)態(tài)注冊(cè)路由 <---------------------------------------- routeAssembler(router); registerRouteFresh = false; next({ ...to, replace: true }); } else { //已經(jīng)登錄了,不能再打開登錄頁 to.path === "/login" ? next("home") : next(); } } else { //如果無須登錄則直接打開,否則轉(zhuǎn)向登錄頁面 to.meta.noLogin || to.path === "/login" ? next() : next("/login"); } }); export default router;
2、如何動(dòng)態(tài)注冊(cè)
src/router/setup.js,即上面例子中的routeAssembler:
/* 裝配路由及菜單 */ import fixItems from "./default"; //默認(rèn)路由 import { HomeName } from "./default"; //統(tǒng)一命名首頁路由項(xiàng)(參考前面的默認(rèn)路由) import projectItems from "@/modules/router"; //具體業(yè)務(wù)系統(tǒng)的路由 export default (router) => { //獲得動(dòng)態(tài)路由 const dynaItems = getDynamicItems(); //對(duì)齊首頁(統(tǒng)一命名首頁) adpatHome(HomeName, dynaItems); //添加動(dòng)態(tài)路由 dynaItems.forEach((value) => { router.addRoute(value); }); }; const getDynamicItems = () => { /* 獲取動(dòng)態(tài)路由,從指定文件加載或從后端獲取 */ return projectItems; }; //默認(rèn)路由與業(yè)務(wù)路由對(duì)齊首頁的路由信息 //所謂對(duì)齊,就是大家的name保持一致,這樣才能保證動(dòng)態(tài)加入的路由項(xiàng),覆蓋掉前面的path和name相同的路由 const adpatHome = (HomeName, dynaItems) => { let home = dynaItems.filter((item) => { return item.path === "/"; }); if (home.length > 0 && home[0].name !== HomeName) { /** * 如果業(yè)務(wù)路由定義了首頁,但其name與默認(rèn)路由首頁的name不相同 * 則將業(yè)務(wù)路由中首頁項(xiàng)的name置為默認(rèn)名稱 * 因?yàn)榘凑誺ue-router的規(guī)則,addRoute的時(shí)候,如果存在同名同路徑的路由項(xiàng),則覆蓋之 * 我們要的就是覆蓋默認(rèn),以業(yè)務(wù)路由設(shè)置為準(zhǔn) */ home[0].name = HomeName; } };
這里面有個(gè)如果動(dòng)態(tài)路由,與默認(rèn)路由中存在相同的路由項(xiàng),該如何處理的問題。
按照vue3的router規(guī)則,如果后面加進(jìn)來的路由項(xiàng),僅僅是path相同,而name不同,則不算是相同的路由項(xiàng),addRoute()進(jìn)去之后,仍然是原先的路由項(xiàng)起作用;但如果是path和name都相同,則原先的會(huì)被覆蓋(我懷疑是name相同就會(huì)被覆蓋)。
所以,默認(rèn)路由中有首頁路由,指向框架代碼中的默認(rèn)首頁;加載動(dòng)態(tài)路由后,該路由被覆蓋,指向了具體業(yè)務(wù)系統(tǒng)的首頁。這也表明,我們無須自己手動(dòng)刪除已加載的同名路由項(xiàng)。
事實(shí)上,刪除還會(huì)報(bào)錯(cuò)。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于vue 添加axios組件,解決post傳參數(shù)為null的問題
下面小編就為大家分享一篇基于vue 添加axios組件,解決post傳參數(shù)為null的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03vue與django(drf)實(shí)現(xiàn)文件上傳下載功能全過程
最近簡單的學(xué)習(xí)了django和drf上傳文件(主要是圖片),做一個(gè)記錄,下面這篇文章主要給大家介紹了關(guān)于vue與django(drf)實(shí)現(xiàn)文件上傳下載功能的相關(guān)資料,需要的朋友可以參考下2023-02-02vue預(yù)覽本地pdf文件方法之vue-pdf組件使用
這篇文章主要介紹了vue預(yù)覽本地pdf文件方法之vue-pdf組件使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03在 Vue 應(yīng)用中使用 Netlify 表單功能的方法詳解
Netlify 帶有內(nèi)置表單處理功能,可以用來存儲(chǔ)表單數(shù)據(jù),下載 csv 文件,同時(shí)可以在接收到新的提交時(shí)發(fā)送郵件通知或者通過配置 webhook 發(fā)送請(qǐng)求。這篇文章主要介紹了在 Vue 應(yīng)用中使用 Netlify 表單功能,需要的朋友可以參考下2019-06-06webpack安裝配置與常見使用過程詳解(結(jié)合vue)
這篇文章主要介紹了webpack安裝配置與常見使用過程,主要結(jié)合vue實(shí)現(xiàn),通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06Vue 實(shí)現(xiàn)樹形視圖數(shù)據(jù)功能
這篇文章主要介紹了Vue 實(shí)現(xiàn)樹形視圖數(shù)據(jù)功能,利用簡單的樹形視圖實(shí)現(xiàn)的,在實(shí)現(xiàn)過程中熟悉了組件的遞歸使用,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05vue3(vite)設(shè)置代理封裝axios api解耦功能
這篇文章主要介紹了vue3(vite)設(shè)置代理封裝axios api解耦,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12