vue 項目封裝 axios 以及調用api自動全局loading、錯誤提示

前言

在項目中使用loading,通常是在js中改一個變量,或者調用一個service中的方法,好比Element Ui中就提供了這兩種方式的loading,這樣作有很好的擴展性。vue

BUT,若是你作一個後臺管理項目,有一個api就要這樣重複一下代碼,emmm...我是接受不了,看我這個懶人是如何在vue項目中,把自動全局的loading封裝到axios中的吧。ios

還有,就是我看不少朋友還在寫這樣的代碼:web

/**
  * 本文簡單設想,後端返回的是比較標準的code、data、message
  */
api.http('url' , data).then(res => {
    if (res.code === 200) {
        // 執行成功的操做
    } else {
        // 錯誤提示,固然這裏只是舉例,並不是說真的alert,可是你每一個請求都要寫,多累啊!
        alert(res.message)
    }
})
複製代碼

準備工做

  • 一個相對標準的vue項目,能夠選擇用vue-cli腳手架構建;
  • 引入axios,理論上直接npm install axios;
  • 建議在項目的src目錄下建立一個utils目錄,能夠分文件去寫一些filter、公共方法等...;
  • utils目錄下建立http.js(想怎麼命名均可以,有意思就行,大家隨意~)

OK,接下來就要在http.js中封裝一下axios.vuex

封裝 axios

這裏話很少說,直接上代碼了vue-cli

import axios from 'axios'
import store from '../store' // 這裏作loading會調用store
import { getToken } from '@/utils/auth' // 這個不重要,就是一個獲取tooken的

// 建立axios實例
const service = axios.create({
  // api的base_url,本地配置的代理,理論上能夠不用baseURL
  // baseURL: process.env.BASE_API, 
  timeout: 15000, // 請求超時時間
  // headers 能夠經過在這裏設置,也能夠在request攔截器裏建立
  // headers: {'X-Custom-Header': 'foobar'}
})

// request攔截器
service.interceptors.request.use(config => {

  // !!! 這裏開始觸發 loading 效果 !!!   
  store.dispatch('SetLoading', true)
  
  // 設置 token header
  getToken() && (config.headers['token'] = token)
  
  // 這個是微信登陸中須要用到 header
  config.headers['deviceType'] = 'school_admin_web' 
  return config
},
error => {
  const { response } = error
  // 這裏能夠根據本身的業務作一些操做,好比說全局提示

  Promise.reject(error)
})

// respone攔截器
service.interceptors.response.use(
  response => {
    // !!! 關閉 loading !!! 
    store.dispatch('SetLoading', false)
    
    const res = response.data
    if (res.code !== 200) {
      // 這裏能夠作一些全局性的錯誤提示,這樣就不必在每一個請求都再寫一個else,再重複代碼提示
      alert(res.message)
      // 不是真的alert啊
    }
    return response.data
  },
  error => {
    // !!! 關閉 loading !!! 
    store.dispatch('SetLoading', false)
    
    const { response } = error
    // 這裏能夠根據本身的業務作一些操做,好比說強制登出
    
    return Promise.reject(error)
  }
)

export default service

複製代碼

好了,能夠看到,其實全局的錯誤提示,在上面的代碼中有直接的體現了,這裏就很少講了,那全局的loading的話,這裏其實調用了store裏的SetLoadingnpm

若是您還沒用過store,請自行學習文檔,這裏不作store的詳細講解。axios

使用 store 控制 loading 狀態

這裏,假想您已經熟悉store並使用store的模塊化(固然,不模塊化也無所謂,看你本身)。 假設store目錄下有個 app module對應的是app.js,好了,上代碼:後端

const app = {
  state: {
    requestLoading: 0,
  },
  mutations: {
    SET_LOADING: (state, boolean) => {
      boolean ? ++state.requestLoading : --state.requestLoading
    },
  },
  actions: {
    SetLoading ({ commit }, boolean) {
      commit('SET_LOADING', boolean)
    },
  },
}

export default app

複製代碼

結合對axios的封裝代碼能夠看到,在axiosrequest攔截器中,我調用了store SetLoading,改變了requestLoading的數值,使其自加1;在response攔截器中,我一樣調用了store SetLoading,改變requestLoading的數值,使其自減1。其總體原理,相似於垃圾回收機制,這樣作的好處是,有多個請求併發時,只有全部的請求都返回結果後,loading效果纔會消失。api

那麼,如今焦點只處於storeapp模塊的requestLoading狀態,咱們拿這個判斷loading效果便可。bash

那麼,剩餘的代碼,這裏就很少說了,

大抵是你在你的佈局層裏,定位一個陰影層的loading,經過requestLoading的狀態,來判斷顯示隱藏(相似於這樣)。

<template>
  <section class="app-main">
    <div class="request-loading" :class="{'request-loading-show' : requestLoading}">
      <div class="loading-module"></div>
    </div>
    <transition name="fade-transform" mode="out-in">
      <router-view/>
    </transition>
  </section>
</template>
<script>
import { mapGetters } from 'vuex'

export default {
  name: 'AppMain',
  computed: {
    ...mapGetters([
      'requestLoading',
    ]),
  },
}
</script>
// .request-loading-show樣式代碼這裏就不寫了,本身根據須要弄一下吧。
複製代碼

最終使用

這裏也不用多說了,就是把第二部封裝好的axios import 使用就OK,這裏建議在src下建立api目錄,來模塊定義全部的api,好比:

import http from '@/utils/http'

export default {
  add (data) {
    return http({ url: '...', data: data, method: 'post' })
  },
}
// 而後在組件里正常調用便可...
複製代碼

總結

經過以上的操做,有兩個好處,請求期間會自動顯示loading效果;當有錯誤時,全局已經作好了提示。

懶,即行爲懶,並不表明思惟懶;

懶得行爲,纔會推進思惟去成就懶...

若是有寫的不對的地方,歡迎提出~

若是您有更好的建議,歡迎留言溝通~

相關文章
相關標籤/搜索