从壹开始 [vueAdmin后台] 之三 || 动态路由配置 项目快速开发
回顧
今天VS 2019正式發布,實驗一波,你安裝了么?Blog.Core 預計今天會升級到 Core 3.0 版本。
?
哈嘍大家周三好!本來今天呢要寫 Id4 了,但是寫到了一半,突然有人問到了關于 Blog.Admin 管理后臺的一些問題,想著這個前后端系列是第一個項目,而且是以后學習的基礎,不能草草了事,所以就把重心往 Blog.Core + Blog.Admin 兩個項目上靠攏了下,明天再更新 IdentityServer4 吧,因為從上周末到今天,這幾天修改了一些東西,這里就不一一的寫文章了,如果你是跟著系列看的小伙伴,應該知道我寫的是什么意思,如果是路人,額不敢保證你能看懂我在說什么,總結來說有以下五點:
?
1、Blog.Core 項目增加了單元測試項目 Blog.Core.Tests ,不過就幾行代碼,做了個小測試而已;
?
2、Blog.Core 項目配置了 AOP Sql 的功能,就是大家在操作倉儲的時候,會生成指定的Sql語句,保存到日志中,方便查看,這是SqlSugar的核心功能;
?
?
3、Blog.Core 項目增加多線程日志功能,防止出現死鎖,可以查看 BlogLogAOP.cs ,當然你可以封裝起來;
?具體查看方法:static void OutSql2Log(string dataIntercept)
?
4、DDD開發之 Christ3D 項目完成了末尾開發,實現了 Identity 登錄(注意不是 Id4 ),并完成部署:
地址:http://123.206.33.109:4773
?
5、Blog.Admin 項目實現數據庫配置動態路由,這個是今天的重點內容,其他的都很簡單,大家看看就行。
然后也簡單說說,如何在 Blog.Admin 項目中,快速添加頁面,雖然這個真的很簡單。
?
好啦,馬上開始今天的 Share Time。
因為這個系列我還沒有寫過一些文章,所以今天就把兩種寫法都寫上,既補充了之前的方案,又設計新的方案。
?
一、傳統的權限路由是如何設計的?
首先先來個動圖(注意這個方案已經棄用了,看看個過程即可,下邊第二節有個動圖,才是以后開發的模板):
?
?
?
1、設計頁面
?這個步驟很簡單,也很普通,我們開發項目,肯定需要設計頁面了,這個不屬于權限路由的一部分,
不過要說的就是,這個頁面路徑的設計,要考慮清楚,有的小伙伴,習慣一股腦全部并列放頁面,也有詳情頁用 detail.vue 或者 id.vue ,還有的是 _id.vue 的,具體的這些規則,需要好好想想,設計清楚,不細說。
?
2、路由實例配置
?(?routerManuaConfig.js 文件?)。相信這個路由大家都已經很明白了,只要是寫過 vue 的,有一點點基礎的,項目初期,我們每次開發頁面,如果需要在項目中使用,就必須將路由實例添加到 Vue 實例里,其實說白了,就是一個對象,這樣 Vue 實例才能調用,也就是能通過 url 訪問到我們的頁面。這個其實是很合理的,也是很正確的,官方也是這么處理的,比如我的 Blog.Admin 項目中,就是這么配置的:
?
可是,嗯,就怕可是,現在我的頁面大概有十多個,就已經一大串了,有時候修改一個路由,需要找半天,這個設計貌似不是隨著項目的擴大,越來越不合理,我見過一個項目,頁面有50+,那配置了一大大大頁的路由 json,嗯,感覺會有解決方案的,沒錯,vue 官方也說提到了,具體的,下文會詳細說明,咱們先安裝這個方案進行下去。
那既然是權限路由,路由有了,就該權限了。
?
3、配置權限菜單(路由)
( Login.vue 、App.vue 文件)雖然我已經覆蓋了 GitHub 上的代碼,但是這個方案的寫法還保留著,大家如果真的就喜歡這種配置,也可以看看。
?上邊我們是把所有的路由都注入到了 Router 實例里,那如何渲染權限菜單呢,沒錯,思路很簡單:
1、當前用戶登錄;
2、獲取到用戶標識,比如 Id ;
3、根據用戶標識獲取權限菜單的 Json 數據;
4、根據 Json? 數據,渲染到左側菜單上。//查看 App.vue 文件中的 routes 這個數組。
?其實前三步都是在 Login.vue 頁面內進行的,很簡單的兩個方法 GetNavigationBar() ,自己看看即可。
?
4、菜單表中,添加新建的頁面菜單
上邊的步驟中,僅僅是將之前的頁面渲染出來了,如果我們新建了一個頁面,新的頁面還沒有顯示出來,
所以就需要在后臺管理 -> 菜單權限管理 -> 菜單管理中,新建一條數據:
?
5、角色與菜單的分配
上邊菜單數據配置好后 ,就需要對當前用戶所對應的角色,進行權限的再次分配了,這個很好理解,這個是核心,前邊所以的操作都是給這個做鋪墊的:
?
6、存在的小問題
其實關于權限路由,上邊五步走已經實現了,是不是感覺很簡單(這里只說菜單,不說API權限問題,這個是上一篇的《二 || 完美實現 JWT 滑動授權刷新》已經說到了),但是現在面臨著兩個問題:
1、就是上邊提到的,需要將很多的路由一一的配置好,注入到路由實例;
2、因為這樣是一次性把全部的路由都注入,如果當前用戶沒有這個頁面的權限,雖然左側的菜單看不到這個頁面,但是如果他強行訪問這個url的話,還是會出現的;
當然我們設計了 api 權限,他看不到內容,但是再強行訪問這個URL的時候,還是會在當前頁面停留,并看到頁面骨架(就是沒有數據,但是有按鈕啥的),
當然我們可以讓用戶直接跳轉到403頁面,嗯,也是一個辦法。
?那有沒有什么辦法,可以動態的生成路由實例呢?欸,要是有這個想法,就是人才,請往下看。
?
二、動態生成路由實例
?上邊我們研究了一般實現權限路由菜單的方法,很簡單,很直觀,但是有兩個小問題,其實對我來說,主要的還是手動配置路由的問題,頁面現在的太多,每次開發一個頁面,不僅需要添加路由,還需要在菜單表里,增加該菜單,然后對權限勾選該菜單,從這個邏輯來看,好像在vue項目中,配置路由就成了冗余的一步了,那如果不配置了,我們該怎么辦呢?這就是今天要說的重頭戲 —— 動態路由實例。
?
首先再來個動圖,以后就用這個方法進行快速開發了:
?
?
?上邊的這個已經對當前路由頁面做了權限匹配,我們匹配好了頁面,剩下的就是開發 API 接口了,開發成功后,要注意兩點:
1、增加接口的授權特性;
?
2、后臺對路由進行編輯,增加api接口;
?
?
1、在路由實例中注入項目基礎路由
?這里要說的重點是 基礎路由 ,那什么是基礎路由呢?就是我們在項目啟動的時候首次運行的頁面(比如登錄頁),或者不需要參與數據庫權限配置的某些路由(比如歡迎頁,404頁),比如我將基本的路由實例重新整理如下:
在項目的 src 文件夾下,新建一個 router 文件夾,然后新建主程序文件 —— index.js ,這個文件以后就是我們的新的路由方案,用來替換之前的 router.js(現在更名為 routerManuaConfig.js )
?
?大家可以看到,現在除了這幾個基礎路由,其他的都被刪除了,統一通過動態注入的方式添加。
?
2、根據環境配置導入組件文件
?這里其實是一個小坑,以前沒有研究過,后來搜索了下,才知道的,原來 vue 動態導入 vue 文件,在不同的環境還不一樣,所以這里特別用了一節來說明下,雖然內容很簡單:
還是在 src/router 文件夾下,建立兩個文件,然后定義導入方法:
?
_import_development.js //開發環境導入組件 module.exports = file => require('@/views' + file + '.vue').default_import_production.js //生產環境導入組件 module.exports = file => () => import('@/views' + file + '.vue')?
那如何進行導入呢,就是下邊的重頭戲了。
?
3、動態生成權限路由(核心)?
這個具體的code 在 src 的根目錄下的 promissionRouter.js 文件里,
A、組件導入 ——?_import
這個其實很簡單,只需要根據當前的環境變量,獲取指定的導入方案,傳入路徑地址作為參數,就可以很好的實現當然地址的注入。
//獲取組件的方法 const _import = require('./router/_import_' + process.env.NODE_ENV)// .......//導入路徑下的組件 route.component = _import(route.path)?
B、獲取數據與保存鉤子 ——?router.beforeEach
?這個是一個核心,就是我們每次在路由切換的時候,都需要動態處理路由實例,這里還有點兒瑕疵,我會在以后慢慢完善,但是思路就是這樣的,這里的路由數據來自兩個方面,一個是api接口獲取,一個是將獲取到的數據存放在本地:
var storeTemp = store; router.beforeEach((to, from, next) => {//動態添加路由 {//不加這個判斷,路由會陷入死循環if (!getRouter) {if (!getObjArr('router')) {var user = window.localStorage.user ? JSON.parse(window.localStorage.user) : null;if (user && user.uID > 0) {var loginParams = {uid: user.uID};getNavigationBar(loginParams).then(data => {console.log('router before each get navigation bar from api succeed!')if (data.success) {getRouter = data.response.children//后臺拿到路由saveObjArr('router', getRouter) //存儲路由到localStoragerouterGo(to, next)//執行路由跳轉方法 }});}} else {//從localStorage拿到了路由getRouter = getObjArr('router')//拿到路由 routerGo(to, next)}} else {console.log(to)if(to.name&&to.name != 'login'){getRouter = getObjArr('router')//拿到路由global.antRouter = getRouterrouterGo(to, next)//執行路由跳轉方法 }next()}} });具體的寫法都很簡單,就是判斷和保存到路由,不細說了,大家pull 下代碼,看看即可。
?
?
C、路由過濾 ——??filterAsyncRouter
?這里要說下,這個是關鍵,因為我們獲取到的,僅僅是一個json格式的權限列表,我們的路徑還是一個字符串 url ,但是我們的動態路由,需要一個?component ,也就是剛剛我們獲取到的對應組件,所以,我們需要來一個過濾器,將獲取到的json數據中,每一個菜單,都添加進去一個 component 組件信息。
//遍歷后臺傳來的路由字符串,轉換為組件對象 function filterAsyncRouter(asyncRouterMap) {//注意這里的 asyncRouterMap 是一個數組const accessedRouters = asyncRouterMap.filter(route => {if (route.path) {if (route.path === '/') {//Layout組件特殊處理route.component = Layout} else { route.component = _import(route.path)}}if (route.children && route.children.length) {route.children = filterAsyncRouter(route.children)}return true})return accessedRouters }?
?
D、生成路由實例與運行 ——?routerGo
?上邊所有的工程中,我們把路由已經生成好了,就剩下最后一步注入到實例里,沒錯,就是紅色的部分,是不是很簡單:
function routerGo(to, next) {getRouter = filterAsyncRouter(getRouter) //過濾路由router.addRoutes(getRouter) //動態添加路由global.antRouter = getRouter //將路由數據傳遞給全局變量,做側邊欄菜單渲染工作next({...to, replace: true}) }?
4、遺留問題——重登新用戶路由不同步
這個是個很搞笑的問題,怎么說搞笑呢,好像上邊的 addRoutes 這個方法設計之初,沒有設計過動態刪除?額好吧,我就是開個玩笑,對尤大大的框架,還是很給力的。
現在有一個問題,就是我現在是test賬號,然后沒有 測試管理 這一組,這個期間我刷新了頁面,然后當我切換超級管理員 blogadmin 的時候,雖然有這個左側菜單,但是點擊測試頁面1的時候,提示404,證明啥,證明這個路由雖然渲染出來了,但是沒有導入到路由實例里,路由對象里,還是之前的,這個時候,必須刷新一下才能正常訪問,請看:
?
?
這個時候我研究出來兩個方案,雖然兩個在本地都可以,但是第二種在發布模式下不行,也就是dist 上傳到服務器就不行了,這里做下記錄,暫時使用第一種方案,可能你遇不到。
1、在系統登出,也就是退出登錄的時候,刷新頁面,使用?window.location.reload(),在 App.vue 的logout 方法里;
2、使用 router.matcher 來替換,在 router/index.js 下的 resetRouter方法,和調用處:promissionRouter.js 下的 routerGo 方法里調用;
目前一切正常,就暫時使用刷新頁面的第一種方案,第二種以后慢慢研究。
您可參考這個issues
?
三、支持多級菜單——遞歸
這個其實很簡單,以前我的版本只是支持兩級菜單,那如果想實現無限級別的多級菜單的話,就肯定需要用到遞歸的概念了,簡單來說,就是——遞歸組件。
具體的原理相信有一點基礎的小伙伴都能理解,就是寫一個遞歸組件,將路由菜單 JSON 給遞歸渲染出來即可:
1、設計菜單遞歸組件
在 src -> components -> 下,新建 Sidebar.vue 組件,實現自身嵌套遞歸:
<template><div><template v-if="item.children"><el-submenu :index="item.id+'index'" v-if="!item.leaf"><template slot="title"><i class="fa" :class="item.iconCls"></i><span class="title-name" slot="title">{{item.name}}</span></template><template v-for="child in item.children"><!-- 這里實現自己遞歸嵌套 注意這個名稱 --><sidebarv-if="child.children&&child.children.length>0":item="child":key="child.path+'5'"/><el-menu-item v-else :key="child.path+'5'" :index="child.path+'5'"><i v-if="child.children&&child.children.length>0" :class="item.iconCls"></i>{{child.name}}</el-menu-item></template></el-submenu></template> <!-- 沒有子節點,直接輸出 --><template v-else><el-menu-item :index="item.path"><i class="fa" :class="item.iconCls"></i><template slot="title"><span class="title-name" slot="title">{{item.name}}</span></template></el-menu-item></template></div> </template><script>export default {name: 'Sidebar',props: {item: {type: Object,required: true}}} </script>?
2、在App.vue 中進行調用
當然,你也可以放到模板組件,也就是 Layout.vue 中調用,把左側菜單,頁頭,頁腳放到 Lauout 布局頁,不過我都放到了 App.vue 了:
<el-menu :default-active="$route.path"class="el-menu-vertical-demo" @open="handleopen" @close="handleclose" @select="handleselect"unique-opened router :collapse="isCollapse"background-color="#2f3e52"text-color="#fff"active-text-color="#ffd04b"><sidebar v-for="(menu,index) in routes" :key="index" :item="menu" /></el-menu>?
記得導入組件:
?
來看看最終的效果吧:
?
?
?
四、結語
?好啦,今天的文章,就先寫到這里吧,最近比較累心,感覺努力付出和收獲不是正比,雖然還在學習,還是想要歇一歇了。
今天的所有內容都已經提交到 Github,然后在線 demo 也做了改變,大家可以自行查看。
?
五、Github && Gitee
?
.NET CORE 源碼:
Github:??https://github.com/anjoy8/Blog.Core
Gitee :? ?https://gitee.com/laozhangIsPhi/Blog.Core
?
VUE 項目開源代碼:
https://github.com/anjoy8/Blog.Vue
?
---???? ---
轉載于:https://www.cnblogs.com/laozhang-is-phi/p/10643993.html
總結
以上是生活随笔為你收集整理的从壹开始 [vueAdmin后台] 之三 || 动态路由配置 项目快速开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: smartadmin官网_smartad
- 下一篇: VoLTE call对应QXDM分析