需求是实现在每次后台请求数据时显示加载动画,请求完成动画消失。
实现方法可以借助之前的axios拦截器,在请求前显示动画,请求结束清除动画。
axios.interceptors.request.use( (config) => { // 所有请求之前都要执行的操作 //根据接口传入参数显示加载动画 showFullScreenLoading(); return config; }, function (err) { return Promise.reject(err); } ); //http response 拦截器 axios.interceptors.response.use((response) => { // 所有请求完成后都要执行的操作 //暂停加载动画 tryHideFullScreenLoading(); return response; }, function (err) { if (err.response) { switch (err.response.status) { case 401: // 返回 401 清除token信息并跳转到登录页面 store.dispatch("logout"); router.replace({ path: 'login', query: { redirect: router.history.current.fullPath } }); } } return Promise.reject(err); });
因为我使用的是CDN引入的ElementUI,所以loading动画实现方式为:
则elementUI显示loading加载动画方法为:
let loading;
function startLoading() { loading = Vue.prototype.$loading({ lock: true, text: "加载中...", background: "rgba(0, 0, 0, 0.8)" }); }
清除loading加载动画方法为:
function endLoading() { loading.close(); }
但是需要考虑一个问题,可能同时发起多个请求,而我们显示动画是一次性的,即等当前所有请求完毕后在清除动画。
//声明一个对象用于存储请求个数 let needLoadingRequestCount = 0; function showFullScreenLoading() { if (needLoadingRequestCount === 0) { startLoading(); } needLoadingRequestCount++; }; function tryHideFullScreenLoading() { if (needLoadingRequestCount <= 0) return; needLoadingRequestCount--; if (needLoadingRequestCount === 0) { endLoading(); } };
目前这个加载动画是全屏 Loading,我的项目是属于后台管理系统,页面头部和菜单栏是不会变化的,所以只需要在主界面里面做动画加载即可。设置的方法是在loading配置参数中添加target来控制。
function startLoading() { loading = Vue.prototype.$loading({ lock: true, text: "加载中...", background: "rgba(0, 0, 0, 0.8)", target: document.querySelector('.loadingtext')//设置加载动画区域 }); }
至此,还存在一个优化问题,当请求响应很快时,页面会出现闪屏现象,其实是loading加载动画显示后又很快的被清除,就会出现闪屏现象。解决思路是在加载动画中做个延迟如果响应超过某个时间段再显示loading否则就不出现。目前还没想到比较好的解决方法。