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;
                    } 
                })             
        }
    }
}
相关文章
相关标签/搜索