首先,在Store中定义 loading.ts

import * as _ from 'lodash-es'
import { defineStore } from 'pinia'
import { ref } from 'vue'
 
export const useLoading = defineStore('loading', () => {
  const loading = ref<boolean>(false)
  const loadingCount = ref<number>(0)
 
  function showLoading() {
    loadingCount.value++
    if (loading.value) return
    loading.value = true
  }
 
  const tryHideLoading = _.debounce(() => {
    loading.value = false
  }, 300)
 
  function hideLoading() {
    if (--loadingCount.value > 0) return
    tryHideLoading()
  }
 
  return { loading, showLoading, hideLoading }
})

然后,再在 api.ts 的拦截器中使用。

import pinia from '@/stores'
import { useLoading } from '@/stores/loading'
import type {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios'
import axios from 'axios'
const { showLoading, hideLoading } = useLoading(pinia)
 
//...
class Api {
  // request 拦截器
  static setRequestInterceptor(instance: AxiosInstance) {
    instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        showLoading()
        return config
      },
      (error: object) => {
        hideLoading()
        return Promise.reject(error) // 在调用的那边可以拿到(catch)你想返回的错误信息
      },
    )
  }
  
  // response 拦截器
  static setResponseInterceptor(instance: AxiosInstance) {
    instance.interceptors.response.use((response: AxiosResponse) => {
      hideLoading()
      //...
    })
  }
  //...
}
export default Api

最后,在需要的地方添加全局 loading。

<div class="form" v-loading="props.attributes?.showLoading && loading"><div>
import { storeToRefs } from 'pinia'
const { loading } = storeToRefs(useLoading())

扩展阅读