vuex在項目中使用的一點總結

如下爲vue後臺管理項目中使用vuex的一點總結,截取了其中部分代碼,若有什麼錯誤,還望指出。javascript

1. token 存儲

登錄成功以後,須要把獲取到的 token 存儲到 vuex 中,配合 axios(或其餘 ajax 庫)的攔截器每次請求前加到 header 中傳給後臺。不過光放在 vuex 是不行的,由於考慮到瀏覽器會刷新,當用戶手動刷新了瀏覽器以後,vuex 中的狀態就會重置。因此當刷新頁面以後,因爲 token 丟失,後臺接收不到 token 會返回 401 到前臺,而前臺檢測到狀態 401 則會跳轉到登陸頁,因此每次刷新就會回到登陸每次刷新就會回到登陸。

爲了解決這個問題,要配合:

  • 本地存儲 localStorage 或者 sessionStorage
  • 對象的 get, set 屬性。
/*  state.js */
export default {
    get UserToken() {
        return sessionStorage.getItem("token");
    },
    set UserToken(value) {
        sessionStorage.setItem("token", value);
    }
}

/* mutation.js */
export default  {
    LOGIN_IN(state, token){
        state.UserToken = token;
    },
    LOGIN_OUT(state){
        state.UserToken = null;
    }
}

/* axios response攔截器 */ 
instance.interceptors.response.use(function (response) {
    return response.data;

}, function (error) {
    if (error.response.status == 401){
        Message({
            type: "warning",
            message: "受權失敗,請從新登陸"
        });
        store.commit("LOGIN_OUT");
        router.replace({path: '/login'})
    }else{
        return Promise.reject(error);
    }
});
能夠發現,這樣一來,雖然咱們從 vuex 中取數據,但實際上咱們操做的都是 sessionStorage。因爲 sessionStorage 在瀏覽器關閉以前都是有效的,即便是刷新了,仍是能從 sessionStorage 獲取到 token,從而防止了刷新回到登錄的問題。

2. 用戶權限

登錄以後會從後臺獲取到當前用戶的權限數組,一樣的咱們也是存儲到 vuex 裏,不過這個就不須要什麼 get set 了,直接存就能夠了。
/*  state.js */
    export default {
        permissionList: null
    }

/* menuNav.vue */
<template>
    <div class="navList">
        <ul>
            <li v-for="item in permissionList">{{item.name}}</li>
        </ul>
    </div>
</template>

<script>
export default {
    computed: {
        permissionList() {
            return this.$store.state.permissionList;
        }
    }
}
</script>

權限有2個問題須要考慮:

  • 刷新後vuex存放的權限數組丟失;vue

  • 用戶手動輸入地址進入沒有權限的路由,好比沒有 /admin 路由的用戶在瀏覽器修改了路由爲 /adminjava

    對於第一個問題,能夠在每一個路由進入前判斷是否存在權限數組,ios

    若是沒有:則去獲取;ajax

    若是有:就進行第二個問題的判斷。vuex

    爲此,咱們須要對在路由的配置時,標識路由是否須要權限,若是須要,而且當前用戶沒有權限,則不讓其進入。element-ui

    因爲後臺返回的權限數組極可能是存在二級,三級,爲了方便用數組進行權限判斷,能夠配合store.getters,用遞歸的方式將其轉化爲一維數組並存到store.getters中,在進入每一個路由前經過Array.includes來判斷是否存在當前權限。axios

router.beforeEach((to, from, next) => {  
    /*  判斷路由是否須要登陸,若是須要且無token回到登陸 */
    if (to.matched.some(record => record.meta.requiresAuth)) {
        if (!store.state.UserToken) {
            next({
                path: '/login'
            })
        } else {
            /* 若是沒有權限列表先獲取 */
            if (!store.state.permissionList) {
                store.dispatch("fetchPermissionList", next());
            } else {
                var userAllPermission = store.getters.userAllPermission;
                
               /* 判斷是否存在*/
                var isExist = userAllPermission.includes((item) => {
                    return to.name==item.name
                });
              
                /*  有當前路由的權限才進入,不然404 */
                if (isExist) {
                    next();
                } else {
                    next({path:'/404'});
                }
            }
        }
    } else {
       /*  除了登陸頁,無需權限的均可進入 */
        if(to.path!="/login"){
            next();
        }else{
            /*  有token再也不進去登陸頁,回到以前的頁面 */
            if(store.state.UserToken){
                next(from.fullPath);
            }
        }     
    }
})

固然,也能夠經過this.$router.addRoutes來動態添加路由。

3. 多個頁面通用數據

項目中一般會有一些各個頁面共用的數據,好比省份城市列表。爲了減小請求,城市都是等到點擊對應的省份時纔去獲取的。

相似這種東西,就能夠放到vuex中來維護,頁面都共享一份數據,這樣一來無疑能夠減小一些沒必要要的請求。不然,若是每一個頁面都存一份單獨的數據,假設A頁面請求了廣東省的城市,B,C頁面須要時,因爲每一個頁面的數據是單獨的,B,C又分別須要去請求一次。而放到vuex來維護,則只須要請求一次就能夠共享了。
/*  state.js */
export default {
    province:[]
}

/*  mutation  */
export default {
    SET_PROVINCE(state, provincelist){
        state.province = provincelist;
    }
}

/*  action.js  */
export default {
    /* 獲取全部省份 */
    fetchProvinceList({
        commit,
        state,
    }) {
        axios
            .get(`/cityRegions`)
            .then(res => {
                if (res.status == 0) {
                    /* 組裝element-ui組件須要的格式 */
                    let province = res.data.map(item => {
                        return {
                            value: item.id,
                            label: item.regionName,
                            children: []
                        };
                    });                   
                    commit("SET_PROVINCE", province);
                } 
            })
    },
    /* 獲取省份下的城市 */
    fetchCityList({
        commit,
        state,
    }, id) {
        /* 找到當前點擊的省份 */
        var parent = state.province.find(item => {
            return item.value == id;
        });
        /* 若是已經有子級城市就再也不請求 */
        if (parent.children && parent.children.length <= 0) {
            axios
                .get(`/cityRegions?pId=${id}`)
                .then(res => {
                    if (res.status == 0) {
                        var city = res.data;
                        city = city.map(item => {
                            return {
                                value: item.id,
                                label: item.regionName
                            };
                        });
                        parent.children = city.length > 0 ? city : null;
                    } 
                })             
        }
    }
}
相關文章
相關標籤/搜索