zoukankan      html  css  js  c++  java
  • vuex在项目中使用的一点总结

    以下为vue后台管理项目中使用vuex的一点总结,截取了其中部分代码,如有什么错误,还望指出。

    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存放的权限数组丢失;

    • 用户手动输入地址进入没有权限的路由,比如没有 /admin 路由的用户在浏览器修改了路由为 /admin

      对于第一个问题,可以在每个路由进入前判断是否存在权限数组,

      如果没有:则去获取;

      如果有:就进行第二个问题的判断。

      为此,我们需要对在路由的配置时,标识路由是否需要权限,如果需要,并且当前用户没有权限,则不让其进入。

      由于后台返回的权限数组很可能是存在二级,三级,为了方便用数组进行权限判断,可以配合store.getters,用递归的方式将其转化为一维数组并存到store.getters中,在进入每个路由前通过Array.includes来判断是否存在当前权限。

    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;
                        } 
                    })             
            }
        }
    }
    
  • 相关阅读:
    Do you want a timeout?
    [整]常用的几种VS编程插件
    [转]Windows的窗口刷新机制
    [整][转]Invoke和BeginInvoke的使用
    [整]C#获得程序路径
    [转]Visual Studio 2010 单元测试目录
    飞秋的实现原理
    面向对象的七大原则
    [转]玩转Google开源C++单元测试框架Google Test系列
    [转]C#中的Monitor类
  • 原文地址:https://www.cnblogs.com/zhengrunlin/p/8760017.html
Copyright © 2011-2022 走看看