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

注: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;

浙公网安备 33010602011771号