vue axios拦截器 + 自编写插件 实现全局 loading 效果;

时间:2023-03-09 02:38:16
vue axios拦截器 + 自编写插件 实现全局 loading 效果;

项目需求:用自定义的 .gif 图标实现全局 loading 效果;为避免在每个页面手动添加,且简单高效的实现,经查阅资料,最终采用了 vue axios拦截器 + 自编写 loading 插件;下面直接贴上代码~

在公用模块定义loading文件,含 index.js,loading.vue文件,文件结构如下:

vue axios拦截器 + 自编写插件 实现全局 loading 效果;

注:loading.vue 与 index.js 之间的传值通过props实现,代码如下:

loading.vue

<template>
  <div class="load-model" v-show="showLoading">
    <img src="../images/loading.gif" alt="loading...">
  </div>
</template>

<script>
export default {
  data(){
    return {

    }
  },
  props:{
    showLoading:false
  }
}
</script>

<style scoped>
.load-model{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  /*background:rgba(255,255,255,0.8);*/
   /* background:rgba(0,0,0,0.6); */
}
.load-model > img{
  width: 12rem;
  height: 12rem;
  margin-top: -5rem;
}
</style>

index.js

let loadTemp = require('./loading.vue').default; // cli3.0以后引入vue模板需要default

let Load = {}; // 定义插件对象
Load.install = (Vue,options) => { // Vue的install方法,用于定义vue插件
  // 如果存在loading 不重复创建DOM
  if(document.getElementsByClassName('.load-model').length) return;

  let lTemp = Vue.extend(loadTemp);

  // 实例化VUE实例
  let $vm = new lTemp();

  // 此处使用$mount来手动开启编译,用$el来访问元素,并插入到body中
  let tpl = $vm.$mount().$el;
  document.body.appendChild(tpl);

  Vue.prototype.$loading = { // 在Vue的原型上添加实例方法,以全局调用
    show(options){
      if(options == "loading"){
        $vm.showLoading = true;
      }
    },
    hide(){
      $vm.showLoading = false;
    }
  }
}

// 导出Load
export default Load;

插件写完后在main.js 中全局调用:

import Loading from './common/loading'

Vue.use(Loading)

这样的话我们就可以在所需要调用的页面调用如下方法:

this.$loading.show("loading"); // 触发 loading 事件
this.$loading.hide(); // 关闭 loading 事件

这样的添加只适用于项目小然后页面比较少的情况下,在大项目下或页面较多的情况下,这样维护起来很繁琐且麻烦,由此我们借用 axios 拦截器,保证统一在一个地方触发与关闭,如下为 axios 拦截器的代码:

开启 loading 效果的代码为:Vue.prototype.$loading.show("loading");

关闭 loading 效果的代码为:Vue.prototype.$loading.hide();

axios_api.js

import Vue from 'vue';
import axios from 'axios';//更改http请求插件
import {Indicator, Toast} from 'mint-ui';

let toast = function (text) {
  Toast({
    message: text,
    duration: 2000
  })
};

// 设置全局的请求次数,请求的间隙
axios.defaults.retry = 1;
axios.defaults.retryDelay = 500;

axios.interceptors.request.use(config => {
  Vue.prototype.$loading.show("loading");
  config.timeout = 60000;
  config.headers['Content-Type'] = 'application/json;charset=utf-8';
  return config
}, error => {
  return Promise.reject(error)
});
axios.interceptors.response.use(response => {
  if (response.status == 200) {
    setTimeout(() => {
      Vue.prototype.$loading.hide();
    },500);
  } else {
    setTimeout(() => {
      Vue.prototype.$loading.hide();
    },500);
    toast('获取数据失败');
  }
  return response;
}, error => {
  // var config = error.config;
  // if (!config || !config.retry) return Promise.reject(error);
  // config.__retryCount = config.__retryCount || 0;
  // if (config.__retryCount >= config.retry) {
  setTimeout(() => {
    Vue.prototype.$loading.hide();
  },500);
  if (error.response) {
    switch (error.response.status) {
      case 0:
        toast('网络连接超时');
        break;
      case 404:
        toast('您请求的功能不存在');
        break;
      case 408:
        toast('请求超时');
        break;
      default:
        toast('请求失败');
        break;
    }
    return Promise.reject(error.response.data);
  } else {
    if (!axios.isCancel(error)) {
      toast('网络连接超时');
    }
    return Promise.reject(error);
  }
  // }
  // config.__retryCount += 1;
  // var backoff = new Promise(function (resolve) {
  //   setTimeout(function () {
  //     resolve();
  //   }, config.retryDelay || 1);
  // });
  // return backoff.then(function () {
  //   return axios(config);
  // });
});

export default axios;