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;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM