zoukankan      html  css  js  c++  java
  • vue的接口封装和状态管理

     

    1.config index.js下面的跨域代理设置:

    复制代码
    复制代码
    proxyTable: {
          '/api': {
            target: 'http://xxxx', //要访问的后端接口
            changeOrigin: true,
            pathRewrite: {
              '^/api': 'http://xxx'
            }
          },
        },
    复制代码
    复制代码

    2.http.js(封装axios)

    复制代码
    复制代码
    import Vue from 'vue'
    import axios from 'axios'
    import QS from 'qs' //视情况用于不用;
    import { Loading, Message } from 'element-ui';
    import store from '../store/index'
    
    let loading //定义loading变量
    
    function startLoading() { //使用Element loading-start 方法
      loading = Loading.service({
        lock: true,
        text: '努力加载中……',
        background: 'rgba(0, 0, 0, 0.5)'
      })
    }
    
    function endLoading() { //使用Element loading-close 方法
      loading.close()
    }
    
    //那么 showFullScreenLoading() tryHideFullScreenLoading() 要干的事儿就是将同一时刻的请求合并。
    //声明一个变量 needLoadingRequestCount,每次调用showFullScreenLoading方法 needLoadingRequestCount + 1。
    //调用tryHideFullScreenLoading()方法,needLoadingRequestCount - 1。needLoadingRequestCount为 0 时,结束 loading。
    let needLoadingRequestCount = 0
    export function showFullScreenLoading() {
      if (needLoadingRequestCount === 0) {
        startLoading()
      }
      needLoadingRequestCount++
    }
    
    export function tryHideFullScreenLoading() {
      if (needLoadingRequestCount <= 0) return
      needLoadingRequestCount--
      if (needLoadingRequestCount === 0) {
        endLoading()
      }
    }
    
    let baseWebURL = '';
    // 环境的切换
    if (process.env.NODE_ENV == 'development') { //开发环境   
      baseWebURL = '/api' + '/api';(多加一个api是后台那边统一拦截处理视项目情况而定加不加)
    } else if (process.env.NODE_ENV == 'test') { //测试环境
      baseWebURL = 'https://www.test.com';
    } else if (process.env.NODE_ENV == 'production') { //生产环境
      baseWebURL = 'http://www.producetion.com';
    }
    //生成一个axios实例
    var instance = axios.create({
      baseURL: baseWebURL,
    });
    console.log(instance, 'instance')
    //1.请求超时时间
    instance.defaults.timeout = 10000;
    //2.post请求头 
    instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
    //3.公共部分(请求带token设置)
    //instance.defaults.headers.common['Authorization'] = store.state.token;
    //4.返回数据类型的定义
    //instance.defaults.responseType = 'json';
    //5.带cookie请求
    instance.defaults.withCredentials = true
    
    // 请求拦截器
    instance.interceptors.request.use(
      config => {
        console.log(config, 'config请求拦截器')
        //1.全局loadin配置
        /*2.token校验:一般是在登录完成之后,将用户的token通过localStorage或者cookie存在本地;
        然后用户每次在进入页面的时候(即在main.js中),会首先从本地存储中读取token;
        如果token存在说明用户已经登陆过则更新vuex中的token状态;
        然后,在每次请求接口的时候,都会在请求的header中携带token;
        后台人员就可以根据你携带的token来判断你的登录是否过期,如果没有携带,则说明没有登录过。
        v1.每次发送请求之前判断vuex中是否存在token        
        v2.如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
        v3.即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断*/
        const token = store.state.token;
        alert(token,'token')        
        token && (config.headers.Authorization = token);
        if (config.method == 'post') {
          console.log('post请求统一需要做什么判断')
        }
        //config.headers.Accept = 'application/json'; //规定接受形式json格式
        showFullScreenLoading() //开启loading
        return config;
      }, error => {
        return Promise.reject(error);
      });
    
    // 响应拦截器
    instance.interceptors.response.use(
      response => {
        console.log(response, 'response响应拦截器')
        // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据     
        //否则的话抛出错误
        if (response.status === 200) {
          tryHideFullScreenLoading() //关闭loading
          Message({
            showClose: true,
            message: '响应成功',
            type: 'success'
          })
          return Promise.resolve(response);
        } else {
          return Promise.reject(response);
        }
      }, error => {
        console.log(error, 'error')
        if (error.response.data.status) {
          console.log('后台错误码统一处理')
          switch (error.response.data.status) {
            // 401:未登录;未登录则跳转登录页面,并携带当前页面的路径;在登录成功后返回当前页面,这一步需要在登录页操作。                
            case 401:
              router.replace({
                path: '/login',
                query: {
                  redirect: router.currentRoute.fullPath
                }
              });
              break;
            // 403:token过期;登录过期对用户进行提示;清除本地token和清空vuex中token对象;跳转登录页面                
            case 403:
              Message({
                showClose: true,
                message: '登录过期,请重新登录',
                duration: 1000,
                type: 'warning'
              })
              //清除token
              localStorage.removeItem('userToken');
              store.commit('LOGIN_OUT', null);
              //跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面 
              setTimeout(() => {
                router.replace({
                  path: '/login',
                  query: {
                    redirect: router.currentRoute.fullPath
                  }
                });
              }, 1000);
              break;
            //404请求不存在
            case 404:
              Message({
                showClose: true,
                message: '网络请求不存在',
                duration: 1000,
                type: 'error'
              })
              break;
            //其他错误,直接抛出错误提示
            default:
              Message({
                showClose: true,
                message: error.response.data.message,
                duration: 1000,
                type: 'error'
              })
          }
        }
        return Promise.reject(error);
      });
    
    
    // 封装axios的get请求
    export function getData(url, params) {
      return new Promise((resolve, reject) => {
        instance.get(url, params).then(response => {
            resolve(response.data);
          })
          .catch(error => {
            reject(error);
          });
      });
    }
    // 封装axios的post请求
    export function postData(url, params) {
      return new Promise((resolve, reject) => {
        instance.post(url, QS.stringify(params)).then(response => {
            resolve(response.data);
          })
          .catch(error => {
            reject(error);
          });
      });
    }
    复制代码
    复制代码

    3.api.js(封装接口)

    import { postData, getData } from './http.js'
    
    export function cityList(data = {}) {
      return postData('/xxxx/xx', data);
    }

    4.vuex构成

    (1)index.js

    复制代码
    复制代码
    import Vue from 'vue';
    import Vuex from 'vuex';
    import state from './state'
    import mutations from './mutations'
    import getters from './getters'
    import actions from './actions'
    Vue.use(Vuex);
    
    const store = new Vuex.Store({
      state,
      mutations,
      getters,
      actions
    });
    
    export default store;
    复制代码
    复制代码

    (2)state.js

    复制代码
    复制代码
    export default {
      state: {
        // 存储token
        token: localStorage.getItem('userToken') ? localStorage.getItem('userToken') : ''
      }
    }
    复制代码
    复制代码

    (3)mutation-types.js (常量)

    export const LOGIN_IN = 'LOGIN_IN';//登入
    export const LOGIN_OUT = 'LOGIN_OUT';//登出

    (4)mutation.js

    复制代码
    复制代码
    import * as type from './mutation-types'
    export default {
      //登入
      [type.LOGIN_IN](state, token) {
        state.token = token;
        localStorage.setItem('userToken', token);
      },
      //登出 or 退出登入
      [type.LOGIN_OUT](state, token) {
        localStorage.removeItem("userToken", token);
        state.token = token;
      },
    }
    复制代码
    复制代码

    (5)actions (这里是异步操作)

    复制代码
    复制代码
    export default{
        //actions这里提交的是mutation
        getLoginInInfo({commit},token){
            commit('LOGIN_IN',token)
        },
        getLoginOutInfo({commit},token){
            commit('LOGIN_OUT',token)
        }
    }
    复制代码
    复制代码

    (6)getters.js  视情况放什么获取state更改后的值

    (7)路由 router下面的index.js

    复制代码
    复制代码
    import Vue from 'vue'
    import Router from 'vue-router'
    import store from '../store/index'
    //方式一:最简单直接的使用组件
    //import HelloWorld from '@/components/HelloWorld'
    //import Test from '@/components/test'
    
    //方式二:webpack自带的模块按需加载 r就是resolve
    //const HelloWorld = r => require.ensure([], () => r(require('@/components/HelloWorld')), 'HelloWorld');
    
    Vue.use(Router)
    
    const router = new Router({
      mode: 'history', //去掉地址栏#号
      routes: [{
        path: '/',
        name: 'testMain',
        meta: {
          title: '系统首页',
          requireAuth: true, // 添加该字段,表示进入这个路由是需要登录的
        },
        component: resolve => require(['@/components/testMain'], resolve) //测试首页
      }, {
        path: '/login',
        name: 'login',
        meta: {
          title: '登入',
        },
        component: resolve => require(['@/components/login'], resolve) //模拟登入------(方式三:懒加载方式)
      }, {
        path: '/HelloWorld',
        name: 'HelloWorld',
        meta: {
          requireAuth: true,
          title: '测试二级联动路由传参',
        },
        component: resolve => require(['@/components/HelloWorld'], resolve) //测试二级联动路由传参
      }, {
        path: '/test',
        name: 'test',
        meta: {
          requireAuth: true,
          title: '测试参数解码',
        },
        component: resolve => require(['@/components/test'], resolve) //测试参数解码
      }, {
        path: '/testEgdit',
        name: 'testEgdit',
        meta: {
          requireAuth: true,
          title: '富文本编辑器试用',
        },
        component: resolve => require(['@/components/testEgdit'], resolve) //富文本编辑器试用
      }, {
        path: '/testElementComponent',
        name: 'testElementComponent',
        meta: {
          requireAuth: true,
          title: 'element ui组件测试',
        },
        component: resolve => require(['@/components/testElementComponent'], resolve) //element ui 组件测试
      }, {
        path: '/tableTest',
        name: 'tableTest',
        meta: {
          requireAuth: true,
          title: 'element ui表格组件测试',
        },
        component: resolve => require(['@/components/tableTest'], resolve) //element ui table组件测试
      }, {
        path: '/echartTest',
        name: 'echartTest',
        meta: {
          requireAuth: true,
          title: 'echart插件测试',
        },
        component: resolve => require(['@/components/echartTest'], resolve) //echart插件测试
      }, {
        path: '*',
        name: 'notFound',
        meta: {
          title: '404页面',
        },
        component: resolve => require(['@/components/notFound'], resolve) //全不匹配的情况下,返回404,路由按顺序从上到下,依次匹配。最后一个*能匹配全部
      }]
    })
    
    router.beforeEach((to, from, next) => {
      //可以做 loadong 开始加载 效果
      store.state.token = localStorage.getItem('userToken'); //获取本地存储的token
      if (to.meta.title) { //判断是否有标题  该操作可以再监听路由时候处理 watch:{'$route'(to,from){xxx操作}}
        document.title = to.meta.title
      }
      if (to.meta.requireAuth) { // 判断该路由是否需要登录权限
        if (store.state.token) { // 通过vuex state获取当前的token是否存
          console.log('有token时候', to, from, next)
          next();
        } else {
          console.log('没有token时候', to)
          next({
            path: '/login',
            query: { redirect: to.fullPath } // 将跳转的路由path作为参数,登录成功后跳转到该路由
          })
        }
      } else {
        next();
      }
    })
    
    router.afterEach(route => {
      //loading加载完成
    });
    
    export default router;
    复制代码
     
     
     
     
     
    « 上一篇: pdf.js使用详解
  • 相关阅读:
    spring注解集合
    spring工作原理理解
    Linux下mysql命令 导入 导出sql文件
    List和Set排序的实现
    LeetCode--树
    LeetCode--链表
    LeetCode--字符串
    LeetCode--贪心算法
    LeetCode--数组
    数据库编程基本练习题
  • 原文地址:https://www.cnblogs.com/onesea/p/13282573.html
Copyright © 2011-2022 走看看