vue-router-power-demo
核心內容有兩點: 一是保持用戶登錄狀態,二是根據登錄用戶的角色動態掛在路由
使用vuex保持用戶登錄
- 點擊登錄按鈕,使用vuex的actions分發登錄操作,發送用戶名和密碼到后臺獲取登錄token, 并存入vuex的state和cookie中
- 使用導航守衛,每次跳轉頁面的時候檢查是否有token,以此來判斷用戶是否登錄
動態掛在路由
- 登錄成功后拉去用戶信息,包括用戶角色,用戶名等
- 根據用戶角色循環判斷預設路由表,將符合要求的路由篩選出來,使用
addRoutes()
動態掛載
src
項目結構
src
│ App.vue
│ main.js
│ permission.js // vue router 守衛導航,對token和role進行判斷
├─api // 統一管理前端與服務器之間的api接口
├─layout // 主視圖的結構管理,包括header,side-bar,main-body等
│ │ index.vue
│ └─components
│ ├─header
│ │ index.vue
│ └─sidebar
│ index.vue
│ side-item.vue // side-bar菜單動態渲染的核心組件
├─mock // 前端模擬服務器獲取數據,modules下的文件名和api接口一一對應
│ │ index.js
│ └─modules
│ getuserinfo.js
│ login.js
│ logout.js
├─router // 路由表,本身只需要一個index,為了結構分離了兩個路由表
│ asyncRoutes.js // 需要動態掛載的路由表
│ constantRoutes.js // 常規路由表,通常為 login、404等一些不需要權限的路由表
│ index.js
├─store // 加載 store 模塊和 getters
│ │ getters.js // 全局getters
│ │ index.js
│ └─modules // 模塊形式的store
│ permission.js
│ user.js
├─style
│ index.scss
├─utils
│ request.js // 封裝了axios,這里只是簡單封裝,但實際項目中肯定有各種需求
└─views // 各個頁面內容├─document│ index.vue├─error-page│ 404.vue├─login│ index.vue├─page1│ index.vue├─page2│ index.vue└─permissionpage.vuesuper.vueuser.vue
敲黑板,劃重點
permission.js
放置全局導航守衛,和文件名含義一樣,對用戶的跳轉行為進行許可判斷,主要是利用vuex.store
中的token和role進行判斷,并完成路由的動態加載行為
store/modules/user.js
用戶的全局狀態,最關鍵的兩個變量,token 和 role 。
token的默認值可以用cookies.get('token')
獲取,因為當頁面刷新時,vuex.store
中的所有狀態都會重置,本身就需要判斷和從cookie中獲取,這樣寫省了一次判斷,而且更為便捷。
actions的內容分發,主要有三個,login
獲取后臺token并保存,getUserInfo
獲取用戶信息并保存,logout
清除本地的token和role等信息
store/modules/permission.js
用于儲存全局路由表,有兩個作用,一是獲取需要動態掛載的路由表,二是用于側邊欄的導航渲染。
actions的主要內容時用role對asyncRoutes
路由表進行篩選
router/constantRoutes.js
和 router/asyncRoutes.js
constantRoutes.js
asyncRoutes.js
這兩個路由表很簡單,本來就是和index.js
一起配置的,但是為了清晰邏輯和結構把這兩個表分離了出來。constantRoutes是默認加載路由,asyncRoutes是需要使用role進行篩選的路由,路由表的結構及配置是需要配合store/modules/permission.js
一起使用。
這里使用的篩選邏輯:對每個route判斷是否配置了meta.roles
,如果沒有,則表示該route全局可用,如果有,再查找meta.roles
中是否有role的值,如果有表示該用戶有使用這個route的權限。
最后很重要的一點,asyncRoutes
路由表的最后需要配置{ path: '*', hidden: true, redirect: '/404' }
,并且只能配置在最后,用來跳轉非合法的url
不在重點中的重點
這個說法有點矛盾,之所以說不在重點中,是因為上面的js中已經完成了用戶的登錄及頁面權限的分配。
但是,我要說但是了,網頁是需要導航頁來引導用戶的,如果將所有連接都放入導航頁,那么沒有權限的用戶點擊會跳轉到404頁,這在用戶體驗上不好,那么就需要在渲染導航頁的時候對role進行判斷。導航頁少的時候還不麻煩,導航頁一多就會顯得十分繁重,而且不易維護。所以使用路由表動態的渲染出導航。
在store/modules/permission.js
的state中有個routes
存儲了該用戶完整的權限路由表,導航菜單就是循環渲染這個路由表,但是該路由表中有許多路由時不需要在導航頁中出現的,比如login,404等。這個時候就需要用到路由表中的hidden
設置了,渲染的時候通過hidden
來判斷是否將該路由渲染到導航菜單中。
官方的標準路由表中是沒有hidden
這個配置的,這個選項其實應該是寫在meta
中的,只是可能為了方便寫在了最外層,網上能找到的很多路由權限實列都是這樣寫的。所以如果有多個導航菜單并存的情況下,hidden
不妨也可以改寫成showOnTop
、showOnSide
,渲染的時候使用對應的選項進行判斷即可。
既然導航菜單是用路由表渲染的,那么路由表的結構和順序就顯得十分重要的,這和渲染出來的導航菜單順序及結構是一直的,復雜的導航菜單通常都有二級菜單和三級菜單,這用到了組件的遞歸,因為比較復雜,所以這個demo只做了簡單的一級導航,目的是為了清晰的展示登錄和頁面權限管理
DEMO預覽地址
DEMO預覽地址
DEMO項目地址
在GitHub上配置的靜態文件的問題記錄:在GitHub的靜態頁面上,頁面內部跳轉沒有問題,刷新后就找不到頁面了。
根本原因在于demo展示的實際地址是https://cliff-rhine.github.io/vue-router-power-demo/
,而vue的路由配置是在根目錄上的,導致在頁面內容跳轉url之后,瀏覽器的url地址已經變成根目錄依賴,而非/vue-router-power-demo/
。所以在刷新頁面時找不到文件。vue-router
的url跳轉機制實際上是html5的history.pushState
和history.replaceState
。
項目在本地配置沒有問題,可以正常刷新頁面
TODO
- 頁面按鈕權限管理