一、背景

在实际项目中,一般都会给页面添加 loading,从而提升用户体验。
添加 loading 的方式有两种(基于vue+element):

1.1 添加到table上

这种方式是将 loading 主要添加到table组件上,并且在一些需要的地方进行单独处理,如给button添加loading效果。

1.2 全局添加

这种方式是根据请求全局添加,只要请求就显示loading。一般在全局的ajax封装中处理。

这里主要介绍的是全局添加的方式

二、有什么问题

根据请求显示loading(用element 的Loading.service()即可实现),在一个请求的情况下,就不会有问题。但是如果存在请求一个接一个(连续请求),就会造成页面闪烁(loading显示 => 关闭 => 马上有显示 => 在关闭 …)。效果如下:
在这里插入图片描述

三、解决方案
3.1 增加两个变量

在store中增加一个变量 isShowLoading 变量,用来控制是否显示loading(最后在store或者storage中增加,因为会在其他组件中使用)

// 第一步:store 文件夹下的state.js
const state = {
  // 控制页面是否正在显示loading
  isShowLoading: false
};

// 第二步:store 文件夹下的mutations.js
const SET_SHOWLOADING = 'SET_SHOWLOADING';
const mutations = {  
  // 设置是否正在加载,显示loading
  [SET_SHOWLOADING](state, data) {
    state.isShowLoading = data;
  }
};

增加一个 loadingCount 变量,用来计算请求的次数

3.2 增加两个方法,来对 loadingCount 进行增减操作
const addLoading = () => {
  // 开始请求时,添加数量,并且设置为显示loading
  loadingCount++;
  store.commit('SET_SHOWLOADING', true);
};
const isCloseLoading = () => {
  // 请求完成或者请求失败时,减少正在请求的数量,并且判断是否还有未完成的请求,如果没有了,则设置为隐藏loading
  loadingCount--;
  if (loadingCount === 0) {
    store.commit('SET_SHOWLOADING', false);
  }
};
3.3 修改axios拦截器
        // 添加请求拦截器
        this.$axios.interceptors.request.use(config => {
            addLoading()
            return config
        }, error => {
            isCloseLoading()
            this.$Message.error('网络异常,请稍后再试')
            return Promise.reject(error)
        })

        // 添加响应拦截器
        this.$axios.interceptors.response.use(response => {
            isCloseLoading()
            return response
        }, error => {
            isCloseLoading()
            this.$Message.error('网络异常,请稍后再试')
            return Promise.reject(error)
        })

如果没有设置请求拦截,则在请求前调用addLoading即可;
请求完成,或者失败都需要调用isCloseLoading
如下:

const request = (method, url, data, config = {}) => {
  // 开启loading,保存正在请求的地址
  addLoading();
  /*
  *	to do list
  *	...
  */ 
  // 最后返回一个promise
  return new Promise((resolve, reject) => {
    axios.request(options)
      .then((res) => {
        const data = res.data;
        if (data) {
          // TODO 判断code,如果由后台统一返回错误信息,则这里统一提示;如果不是,则调用的地方在判断code
          if (data.code === '1') {
            isCloseLoading();
            resolve(data);
          } else {            
            isCloseLoading();
            // TODO 提示message
            Message.error(data.msg || data.error);
            reject(res);
          }
        } else {
          isCloseLoading();
          reject(res);
        }
      })
      .catch((res) => {
        removePending(options.url);
        isCloseLoading();
        // TODO 判断
        reject(res);
      });
  });
};
3.4 在App.vue中处理是否显示loading
<template>
  <div id="app">
    <!-- 路由跳转 -->
    <router-view v-if="isRouterAlive"></router-view>
    <div v-if="$store.state.isShowLoading"
         class="loading">
      <i class="cp-icon">&#xe600;</i>
    </div>
  </div>
</template>
#app {
  height: 100%;
  position: relative;
  .loading{
    width: 100%;
    height: 100%;
    background: rgba(255, 255, 255, 0.6);
    position: absolute;
    top: 0px;
    left: 0px;
    z-index: 9;
    display: flex;
    justify-content: center;
    align-items: center;
    color: $primary;
    font-size: 30px;
    @keyframes  animal {
      0%{
        transform: rotate(0deg);
        -ms-transform: rotate(0deg);
        -webkit-transform: rotate(0deg);
      }
      100%{
        transform: rotate(360deg);
        -ms-transform: rotate(360deg);
        -webkit-transform: rotate(360deg);
      }
    }
    // 自定义旋转动画
    i{
      color: $primary;
      font-size: 40px;
      animation: animal 1.4s infinite linear;
      transform-origin: center center;
    }
  }
}
3.5 最终效果在这里插入图片描述

参考文章:多个请求下 loading 的展示与关闭 ==>> 感谢这位大佬提供了一个很好的思路

文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出

对博客文章的参考,若原文章博主介意,请联系删除!请原谅

Logo

前往低代码交流专区

更多推荐