最近接到一個新的需求,要求將系統的用戶進行分類,用戶登錄後根據不一樣的用戶權限展現不一樣的功能列表。前端
這個功能在後臺管理中很常見,大體的思路是vue
一個在前端生成功能列表,一個在後端返回,兩個本質上相似,最終都是須要獲得一個該用戶的功能列表。可是二者都有一個不可忽視的東西,就是若是用戶直接在地址欄輸入會怎麼樣。vuex
因爲公司項目不算小,爲了後期維護方便,我仍是選擇了使用 vuex 完成上述的功能。後端
主要想法爲在vuex中保存用戶登錄後的狀態,以及用戶可訪問的路由列表,這樣的話,不涉及到父子組件間的數據傳遞,能夠很方便的在單個組件中獲取到用戶的權限路由列表。數組
若是隻是想簡單的使用一個vuex,瞭解state,mutation,action就足夠你使用app
在src文件夾下,建立一個store文件夾,若是項目簡單,能夠將state,mutations,actions,getters等寫入到一個文件中ide
主要代碼很簡單,只須要導入Vue,Vuex,而且調用Vue.use(Vuex)。函數
結合官方解釋的我的理解,一個vuex文件就是一個倉庫,它包含着你須要共享的變量、有關的事件、以及能夠執行這些事件的行爲,咱們把這些導出去,在單個組件中引入,咱們即可以在單個組件中對共享的變量進行改變。工具
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const state = { userLogin:false//共享變量 } export default new Vuex.Store({ state })
state主要功能是用來定義變量,表明你須要共享的一個狀態。好比,我想要在每一個組件中 共享用戶的路由列表,因此,我須要先在state中定義一個存放路由列表的變量。學習
1、vuex文件代碼
store/index.js中
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const state = { pressionList: [{ path: "/A", name: "頁面A" }],//用戶容許登錄的路由列表,爲了方便記錄,我寫了一個默認值,這個能夠不用 userLogin:false//用戶登錄狀態 } export default new Vuex.Store({ state })
2、main.js文件代碼
main.js中直接引入 store文件,並進行全局註冊便可。這樣在每一個組件中你均可以調用state裏的共享變量啦。
import Vuex from 'vuex' import store from './store/index/' Vue.user(Vuex) new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
那怎麼樣在組件中讀出state的變量呢?有兩種方法:直接獲取、或者使用mapState輔助工具。
插播一條題外話
咱們作爲一枚程序猿,必需要試着去讀API,一次讀不懂就多讀幾回。再讀不懂請教別人,再去讀一次,你會發現每次讀都有不一樣的收穫。
如下爲vuex官方API,我會試着帶一點API裏的東西討論此次需求的生成。
https://vuex.vuejs.org/zh/guide/
3、單個組件中讀取state
如下爲官方API提供對state用法的描述。
上半段,將狀態從根組件「注入」到每個子組件,咱們已經在main.js裏完成了。
主要看下半段,在computed屬性裏,監聽state中的變量,而後經過this.$store.state獲取
套入到咱們的需求中,咱們須要獲取用戶的路由列表,以及登錄狀態
3.1 直接獲取
computed: { pressionList(){ return this.$store.state.pressionList }, userLogin(state){ return state.userLogin//或者接收一個state類型的變量,直接調用state裏的共享屬性 } }
此時咱們已經獲取到了state裏的狀態,此時它就像一個data裏定義的變量,咱們可使用數據雙向綁定的形式調用它。如:我想要輸出用戶登錄的狀態。或者在事件中展現這個狀態。
<div>{{userLogin}}</div> methods:{ login(){ console.log(this.userLogin) } }
3.2 藉助mapState輔助工具獲取
假如說state裏保存了不少個共享的狀態,咱們都須要怎麼辦呢,這樣一個一個寫太複雜,這時候,mapState就幫了咱們很大的忙。
仍是先看官方上的文章解釋
咱們須要在組件的內部導入mapState,而後在computed屬性裏監聽,以上圖片無非就是說了幾種狀況
是數組,因此中間是 [],不是{}
有了以上的基礎,咱們能夠獲取到一個共享的狀態了,可是若是咱們須要在共享的狀態上作點小動做怎麼辦呢?
mutation就幫咱們作這些事件,咱們須要把對共享狀態須要作的事件寫到mutation中,而後在組件中調用mutation裏的事件,就能夠了。
一樣的,能夠去官網看一下關於mutation的介紹。這裏就不放圖了,直接上代碼
1、定義mutation
store/index.js
const mutations = { changePressionList(state,list){ state.pressionList = list; } } export default new Vuex.Store({ state, mutations//一樣就 })
mutation裏的事件第一個參數確定是state,用來調用共享的全部變量,後面能夠接收一個其它的參數。
這裏我是須要改變 共享路由的值,因此我須要接收到一個新的值來替換掉舊的值
我的理解時間
mutation是用來定義一個事件的,咱們須要對共享變量作的一系列的動做。可是,這個事件本身是不會去執行的,像methods裏定義的一個事件同樣,你須要去觸發它。而mutation觸發的方法就是用commit。如你想單擊的時候觸發mutation事件,你須要在單擊事件裏使用commit調用 mutation事件。
2、調用mutation
一樣兩種方式,直接調用、藉助mapMutations輔助函數
2.1 直接調用
若是你理解了獲取state變量,這個mutation調用會簡單不少。
既然mutation是一個事件,因此,咱們須要在methods裏去寫
<button @click="changePress">更改用戶路由</button> methods:{ changePress(){ let B= [{ path: "/B", name: "頁面B" }]; this.$store.commit('changePressionList',B) } }
由於個人mutation定義的事件裏接收了一個參數,那我調用的時候就須要傳遞一個參數。
commit 第一個參數是你須要調用的mutation事件,第二個是mutation事件裏須要的一些參數。
點擊頁面上的改變按鈕,你會發現輸出的pressionList變量會發生改變。
我這個只是簡單的用法,還有更深層次的,想學習的能夠去官網查看
2.2 藉助mapMutations輔助函數
也是三種狀況,你能夠以字符串數組的形式調用mutation裏定義的事件,也能夠給事件起一個別名。這個也跟state相似
在須要傳值的狀況下,也可使用字符串數組的形式傳遞。可是調用時,須要傳遞相應的參數。
<button @click="pressionList(list)">改變</button> data(){ return { list:[{ path: "/B", name: "頁面B" }] } } methods:...mapMutations([ 'pressionList' ])
有了state、mutation的基礎,咱們就能夠實現咱們的第一個功能。在用戶登錄成功後,修改userLogin的狀態,而後將用戶的路由列表寫入。
1、定義action
action與mutation相似,可是他是用來提交mutation的。至關於咱們在action裏提交mutation,而後咱們再調用action。
action接收到的第一個參數,是一個與store對象有相同的方法和屬性的context對象,包括commit,state,getters方法等等。
利用解構賦值,咱們也能夠只用context其中的一個方法,如commit,因此咱們會常常的看到({commit,state})樣式的代碼
若是須要傳遞參數,能夠在後面添加
const actions = { changePress({commit},list){ commit('changePressionList',list) } }
2、調用action
與muation不一樣的是,調用action中的事件使用的是dispatch,意思是分發mutation中的事件。
調用方法也是在methods中,分爲兩種,與mutation用法一致。再也不贅述
咱們根據以上的作法,咱們獲得了一個有效的路由列表。咱們能夠在首頁裏循環這個列表,有哪一個路由咱們就渲染哪一個路由
底部路由代碼
即便如此,若是有人直接在地址欄裏輸入了他不能訪問的路由,咱們該怎麼辦呢?
這裏就須要兩個知識
動態添加路由欠着吧~~
改變路由文件很簡單,只須要在路由文件末尾添加一個匹配全部路由的
path爲/* 表示,當用戶在地址欄直接 輸入一個錯誤的地址時,如路由文件中並無abcd這個頁面,可是用戶在地址欄輸入了/abcd,這時會自動跳到登錄頁面。
export default new Router({ routes: [{ path: '/', name: 'Login', component: Login }, { path: '/Father', name: 'Father', component: Father }, { path: '/Child', name: 'Child', component: Child }, { path: '/Home', name: 'Home', component: Home }, { path: '/A', name: 'A', component: A }, { path: '/*', name: 'Login', component: Login } ], mode: 'history' }, )
對我感興趣的盆友,也能夠關注個人我的公衆號---小嘀咕影院官網。會不按期更新技術知識,旅行遊記以及影視推薦