Vue-根據(jù)角色生成動態(tài)路由及菜單-4(完)-完結(jié)動態(tài)路由

1.安裝axios坚芜,創(chuàng)建請求和響應(yīng)攔截器般哼,建立環(huán)境變量文件燥爷,模擬獲得token和userInfo接口。終端中運行 npm i axios 安裝axios谅辣。在/src目錄下創(chuàng)建utils/request.js 用來封裝請求修赞。同時在項目根目錄下創(chuàng)建.env環(huán)境變量文件( .env.development為開發(fā)時環(huán)境變量,.env.production為生產(chǎn)時環(huán)境變量 )桑阶。 axios.create的baseURL使用了環(huán)境變量柏副,因為每次修改環(huán)境變量都需要重新編譯才能生效,所以平時開發(fā)的時候為了省時都是直接在此添加一行實際用到的Url(切記提交代碼前改為使用環(huán)境變量的 (づ╥﹏╥)づ 之前忘記了2次導(dǎo)致生產(chǎn)環(huán)境請求了測試環(huán)境服務(wù)器蚣录,教訓(xùn)案钤瘛)。

image

request.js中主要做了創(chuàng)建axios實例并攔截請求和響應(yīng)萎河,做一些處理荔泳。實際項目中根據(jù)需要在請求攔截中附加token蕉饼,在響應(yīng)攔截中根據(jù)后端返回的響應(yīng)碼做對應(yīng)的處理。

request.js大概代碼:


import axios from 'axios'

import Store from '@/store'

const timeOut = 10000

const axiosInstance = axios.create({

 baseURL: process.env.VUE_APP_BASE_URL,

 withCredentials: true, // send cookies when cross-domain requests

 timeout: timeOut // request timeout 1

})

axiosInstance.interceptors.request.use(

  config => {

   const token = Store.getters.token

   if (token) {

     config.headers['Authorization'] = 'Bearer ' + token

   }

   return config

 },

  error => {

   return Promise.reject(error)

 }

)

axiosInstance.interceptors.response.use(

  response => {

   // console.log(response)

   const res = response.data

   // console.log(res)

   const code = res.code

   if (code === 20000) {

     return res

   } else {

     // TODO 根據(jù)實際項目中接口返回的狀態(tài)碼進(jìn)行處理(比如拿到?jīng)]有token的響應(yīng)跳轉(zhuǎn)login等操作)

     return Promise.reject(res)

   }

 },

  error => {

 }

)

export default axiosInstance

2. 創(chuàng)建測試api玛歌。在src/下創(chuàng)建apis目錄昧港,生成login.js用來處理和登錄相關(guān)的api。這里測試只用了login登錄和getInfo獲得用戶信息兩個接口

image

然后在之前views/Login.vue測試頁面中簡單寫一個輸入用戶名+密碼以及一個登錄按鈕支子。點擊登錄按鈕dispatch登錄操作對應(yīng)的loginFn创肥,拿到token并存儲到state中;后繼續(xù)dispatch獲得用戶信息對應(yīng)的getUserInfo拿到roles和userInfo并存儲到state中值朋。這里獲得token后存到了本地叹侄,取的時候也從本地取,本地沒有時默認(rèn)為''昨登,防止刷新后store中數(shù)據(jù)丟失又需要重新登錄圈膏。

image

import Vue from 'vue'

import Vuex from 'vuex'

import { asyncRoutes, constantRoutes } from '@/router'

import { login, getInfo } from '@/apis/login'

Vue.use(Vuex)

export default new Vuex.Store({

 state: {

   app: {

     sideBarIsCollapse: false, // 左側(cè)菜單欄是否收起

   },

   routes: asyncRoutes.concat(constantRoutes),

   token: localStorage.getItem('token') || '',

   userInfo: null,

   roles: [],

 },

 getters: {

   token(state) {

     return state.token

   },

   roles(state) {

     return state.roles

   },

   routes(state) {

     return state.routes

   }

 },

 mutations: {

   TOGGLE_SIDE_BAR(state) {

     state.app.sideBarIsCollapse = !state.app.sideBarIsCollapse

   },

   SET_ROUTES(state, roles){

     console.log(state, roles)

   },

   SET_TOKEN(state, token) {

     state.token = token

     localStorage.setItem('token', token)

   },

   SET_INFO(state, data) {

     state.userInfo = data

   },

   SET_ROLES(state, roles) {

     state.roles = roles

   },

   LOGOUT(state) {

     state.token = ''

     localStorage.removeItem('token')

   }

 },

 actions: {

   loginFn({ commit }, data) {

     return new Promise((resolve) => {

       login(data).then(res => {

         if (res?.data) {

           commit('SET_TOKEN', res.data)

           resolve(res.data)

           //   dispatch('getUserInfo', res.data)

         }

       })

     })

   },

   getUserInfo({ commit }, token) {

     return new Promise((resolve, reject) => {

       getInfo(token).then(res => {

         // console.log(res)

         if (res?.data) {

           commit('SET_INFO', res.data)

           commit('SET_ROLES', res.data.roles)

           // commit('SET_ROUTES', res.data.roles)

           resolve(res.data)

         }

       }).catch(e => {

         reject(e)

       })

     })

   }

 },

})

Login.vue中dispatch獲得用戶信息后就可以跳轉(zhuǎn)到首頁了。


async handleLogin() {

     const token = await this.loginFn(this.loginForm)

     if (token) {

       const info = await this.getUserInfo(token)

       console.log(info)

       if (info.id) {

         this.$router.push('/')

       }

     }

   }

3. 到這里就只需要根據(jù)用戶的role過濾出他有權(quán)限看的頁面的路由動態(tài)生成左側(cè)導(dǎo)航菜單篙骡,并且使用router.beforeEach路由守衛(wèi)進(jìn)行權(quán)限判斷攔截處理稽坤。

之前為了測試,router/index.js中new VueRouter時傳入的routes為所有路由糯俗,現(xiàn)在改為只傳入不需要權(quán)限就能訪問的constantRoutes尿褪;同時把store/index.js中的state中 routes 改為空數(shù)組;并新增2個方法得湘,調(diào)用getUserInfo后拿到role根據(jù)用戶角色從所有路由中過濾能訪問的路由數(shù)據(jù)賦值給state中的routes杖玲。

image

filterAsyncRoutes方法中,在有子路由即有children情況下使用遞歸處理:


function hasPermission(roles, route) {

 if (route.meta && route.meta.rolesAuths) {

   return roles.some(role => route.meta.rolesAuths.includes(role)) // rolesAuths只要包含roles中任意一個元素即滿足 true

 } else {

   return true // 沒寫權(quán)限的默認(rèn)允許  比如404

 }

}

function filterAsyncRoutes(routes, roles) {

 const res = []

 routes.forEach(route => {

   const tmp = { ...route }

   if (hasPermission(roles, tmp)) { // 父級路由有權(quán)限才處理子頁面權(quán)限

     if (tmp.children) {

       tmp.children = filterAsyncRoutes(tmp.children, roles)

     }

     res.push(tmp)

   }

 })

 // console.log(res)

 return res

}

在/src下生成permission.js進(jìn)行路由守衛(wèi)淘正,并在main.js中引入摆马。代碼僅提供思路參考,實際根據(jù)項目完善異常處理


import store from '@/store'

import router from '@/router'

// 不需要鑒權(quán)的頁面

const whitePagePaths = ['/login']

router.beforeEach((to, from, next) => {

 console.log(to, from)

 const token = store.getters.token

 if (token) {

   if (to.path === '/login') {

     next({ path: '/' }) // 如果是/login, 則跳轉(zhuǎn)到 /, 該跳轉(zhuǎn)動作依舊走一遍 router.beforeEach 邏輯

   } else {

     const roles = store.getters.roles

     if (roles.length > 0) {

       next()

     } else {

       // 如果只有token但是沒有拿到userInfo(比如說刷新了頁面)鸿吆,則重新獲取一次

       store.dispatch('getUserInfo').then(res => {

         if (res) {

           const roles = res.roles

           store.commit('SET_ROUTES', roles)

           const routes = store.state.routes

           routes.forEach(item => {

             router.addRoute(item)   //  !!!! 生成動態(tài)路由的關(guān)鍵api

           })

           next(to.path)

         }

       }).catch(e => {

         console.log(e)

         localStorage.removeItem('token')

         store.dispatch('SET_TOKEN', '')

         router.push('/login')

       })

     }

   }

 } else {

   if (whitePagePaths.includes(to.path)) {

     next()

   } else {

     next(`/login?redirect=${to.fullPaht || ''}`)

   }

 }

})

image

到這里根據(jù)用戶角色生成動態(tài)路由全部實現(xiàn)思路走了一遍囤采。實現(xiàn)方式只是多種優(yōu)秀方式中的一種,這4篇關(guān)聯(lián)文章僅供自己記錄實現(xiàn)思路回顧用惩淳,如有見解歡迎交流

image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蕉毯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子思犁,更是在濱河造成了極大的恐慌代虾,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件激蹲,死亡現(xiàn)場離奇詭異棉磨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)学辱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門乘瓤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來环形,“玉大人,你說我怎么就攤上這事馅扣。” “怎么了着降?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵差油,是天一觀的道長。 經(jīng)常有香客問我任洞,道長蓄喇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任交掏,我火速辦了婚禮妆偏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盅弛。我一直安慰自己钱骂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布挪鹏。 她就那樣靜靜地躺著见秽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讨盒。 梳的紋絲不亂的頭發(fā)上解取,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機(jī)與錄音返顺,去河邊找鬼禀苦。 笑死,一個胖子當(dāng)著我的面吹牛遂鹊,可吹牛的內(nèi)容都是我干的振乏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼秉扑,長吁一口氣:“原來是場噩夢啊……” “哼昆码!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起邻储,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤赋咽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吨娜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脓匿,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年宦赠,在試婚紗的時候發(fā)現(xiàn)自己被綠了陪毡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片米母。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖毡琉,靈堂內(nèi)的尸體忽然破棺而出铁瞒,到底是詐尸還是另有隱情,我是刑警寧澤桅滋,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布慧耍,位于F島的核電站,受9級特大地震影響丐谋,放射性物質(zhì)發(fā)生泄漏芍碧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一号俐、第九天 我趴在偏房一處隱蔽的房頂上張望泌豆。 院中可真熱鬧,春花似錦吏饿、人聲如沸踪危。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陨倡。三九已至,卻和暖如春许布,著一層夾襖步出監(jiān)牢的瞬間兴革,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工蜜唾, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留杂曲,地道東北人。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓袁余,卻偏偏與公主長得像擎勘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子颖榜,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,573評論 2 353