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效果;当有错误时,全局已经作好了提示。

懒,即行为懒,并不表明思惟懒;

懒得行为,才会推进思惟去成就懒...

若是有写的不对的地方,欢迎提出~

若是您有更好的建议,欢迎留言沟通~

相关文章
相关标签/搜索