这篇文章主要介绍了vue+iview项目中全局loading效果的配置问题。

问题描述

vue项目中如果出现了接口嵌套的状况,外层的接口完成后loading效果就消失了,导致页面在请求到内部接口时没有任何效果

问题分析

看了源码发现这个Spin组件销毁组件时延迟了500ms,所以嵌套的接口在内部接口开始调用Spin后马上就要执行销毁操作了。另一个重要的原因是请求接口封装的api的url是固定的导致queue队列中只有一条数据。

解决方法

在每一次请求拦截时把当前url存在一个queue队列中,请求完成无论失败与否都执行销毁操作并从队列中弹出之前存进去的url。这样依然不能达到嵌套接口不关闭loading的效果,还是和一起一样每次有请求都会打开loading,请求结束后销毁loading组件。解决方法就在于在每次弹出操作后延迟100ms再执行销毁操作,这样等待的100ms内如果有新的请求进来就不在执行销毁操作了。这样就可以达到只要嵌套的接口没有全部都完成loading效果就不会关闭。

axios.js配置

import axios from 'axios'
import store from '@/store'
import {Spin} from 'view-design'
const addErrorLog = errorInfo => {
  const {statusText, status, request: {responseURL}} = errorInfo
  let info = {
    type: 'ajax',
    code: status,
    mes: statusText,
    url: responseURL
  }
  if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
}

class HttpRequest {
  constructor (baseUrl = baseURL) {
    this.baseUrl = baseUrl
    this.queue = [] // 20201126存放地址队列
  }
  getInsideConfig () {
    const config = {
      baseURL: this.baseUrl,
      headers: {}
    }
    return config
  }
  destroy (url) {
    this.queue.pop() // 弹出遵循先进先出原则
    setTimeout(() => { // 延迟100ms看看是否是否有嵌套接口
      if (!this.queue.length) { // 如果队列里还有没有完成的请求就不关闭loading效果
        Spin.hide()
      }
    }, 100)
  }
  interceptors (instance, url) {
    // 请求拦截
    instance.interceptors.request.use(config => {
      // 添加全局的loading...
      this.queue.push(url) // 把url添加到队列
      if (this.queue.length) { // 如果队列中有值就打开loading
        Spin.show({
          render: h => {
            return h('div', [
              h('Icon', {
                'class': 'spin-icon-load',
                props: {
                  type: 'ios-loading',
                  size: 30
                }
              }),
              h('div', '加载中...')
            ])
          }
        })
      }
      return config
    }, error => {
      return Promise.reject(error)
    })
      
    // 响应拦截
    instance.interceptors.response.use(res => {
      this.destroy(url) // 成功响应关闭loading
      const {data, status} = res
      return {data, status}
    }, error => {
      this.destroy(url) // 响应失败关闭loading
      let errorInfo = error.response
      if (!errorInfo) {
        const {request: {statusText, status}, config} = JSON.parse(JSON.stringify(error))
        errorInfo = {
          statusText,
          status,
          request: {responseURL: config.url}
        }
      }
      addErrorLog(errorInfo)
      return Promise.reject(error)
    })
  }
  request (options) {
    const instance = axios.create()
    options = Object.assign(this.getInsideConfig(), options)
    this.interceptors(instance, options.url)
    return instance(options)
  }
}
export default HttpRequest

备注

vue-iview-admin@2.0.0

Logo

前往低代码交流专区

更多推荐