vuex根據不一樣的用戶權限展現不一樣的路由列表

需求描述

最近接到一個新的需求,要求將系統的用戶進行分類,用戶登錄後根據不一樣的用戶權限展現不一樣的功能列表。前端

這個功能在後臺管理中很常見,大體的思路是vue

  1. 後臺返回用戶類型,前端根據用戶類型生成該類用戶能夠訪問的功能列表。
  2. 後臺返回功能列表,前端進行循環渲染。

一個在前端生成功能列表,一個在後端返回,兩個本質上相似,最終都是須要獲得一個該用戶的功能列表。可是二者都有一個不可忽視的東西,就是若是用戶直接在地址欄輸入會怎麼樣。vuex

技術選型

因爲公司項目不算小,爲了後期維護方便,我仍是選擇了使用 vuex 完成上述的功能。後端

主要想法爲在vuex中保存用戶登錄後的狀態,以及用戶可訪問的路由列表,這樣的話,不涉及到父子組件間的數據傳遞,能夠很方便的在單個組件中獲取到用戶的權限路由列表。數組

Vuex

若是隻是想簡單的使用一個vuex,瞭解state,mutation,action就足夠你使用app

在src文件夾下,建立一個store文件夾,若是項目簡單,能夠將state,mutations,actions,getters等寫入到一個文件中ide

clipboard.png

主要代碼很簡單,只須要導入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主要功能是用來定義變量,表明你須要共享的一個狀態。好比,我想要在每一個組件中 共享用戶的路由列表,因此,我須要先在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用法的描述。
clipboard.png

上半段,將狀態從根組件「注入」到每個子組件,咱們已經在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就幫了咱們很大的忙。
仍是先看官方上的文章解釋
clipboard.png
咱們須要在組件的內部導入mapState,而後在computed屬性裏監聽,以上圖片無非就是說了幾種狀況

  • 若是你只是想單純的使用state裏的變量,那你用箭頭函數的形式,會更加簡單
  • countAlias:'count'//至關於給state裏的count變量起了一個別名叫countAlias,調用時使用countAlias
  • 若是你須要在共享變量裏添加一個其它的變量做爲返回結果時,這時不可以使用箭頭函數,而是常規的函數才能操做。由於箭頭函數自己是沒有this這個東西噠。
  • 若是state中有不少的變量,並且,你也不打算給它們起別名,或者作其它的操做,你可使用數組的形式。向state傳遞一個字符串的數組,state會本身一一的對應。
    mapState(['pressionList','userLogin'])

clipboard.png是數組,因此中間是 [],不是{}

mutation

有了以上的基礎,咱們能夠獲取到一個共享的狀態了,可是若是咱們須要在共享的狀態上作點小動做怎麼辦呢?
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輔助函數

clipboard.png

也是三種狀況,你能夠以字符串數組的形式調用mutation裏定義的事件,也能夠給事件起一個別名。這個也跟state相似

  • 事件不須要起別名,事件名與mutation名一致,而且沒有接收變量這種狀況下,可使用
    ...mapMutations(['changePressionList'])
    注意,這裏是[],以字符串數組的形式調用
  • 在須要傳值的狀況下,也可使用字符串數組的形式傳遞。可是調用時,須要傳遞相應的參數。

    <button @click="pressionList(list)">改變</button>
    data(){
        return {
            list:[{ path: "/B", name: "頁面B" }]
        }
    }
    methods:...mapMutations([
        'pressionList'
    ])
  • add:'increment' 至關於給mutation中定義的increment事件起了一個add別名,在組件中調用時,直接調用 add便可。

action

有了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用法一致。再也不贅述

路由限制

咱們根據以上的作法,咱們獲得了一個有效的路由列表。咱們能夠在首頁裏循環這個列表,有哪一個路由咱們就渲染哪一個路由
底部路由代碼

clipboard.png
即便如此,若是有人直接在地址欄裏輸入了他不能訪問的路由,咱們該怎麼辦呢?
這裏就須要兩個知識

  • 動態添加路由
  • 改變路由文件

動態添加路由欠着吧~~

改變路由文件很簡單,只須要在路由文件末尾添加一個匹配全部路由的
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'
}, )

我的公衆號

對我感興趣的盆友,也能夠關注個人我的公衆號---小嘀咕影院官網。會不按期更新技術知識,旅行遊記以及影視推薦

clipboard.png

相關文章
相關標籤/搜索