在vuex 设置 loading 状态处理
import { Module } from 'vuex'
import { GlobalDataProps } from './index'
export interface GlobalStatus {
opNames: { [key: string]: boolean };
requestNumber: number;
error: {
status: boolean;
message?: string;
};
}
const global: Module<GlobalStatus, GlobalDataProps> = {
state: {
requestNumber: 0,
opNames: {},
error: {
status: false
}
},
mutations: {
startLoading (state, { opName }) {
state.requestNumber++
if (opName) {
state.opNames[opName] = true
}
},
finishLoading (state, { opName }) {
setTimeout(() => {
state.requestNumber--
delete state.opNames[opName]
}, 1000)
},
setError(state, e) {
state.error = e
}
},
getters: {
isLoading: (state) => {
return state.requestNumber > 0
},
isOpLoading: state => (opName: string) => {
return state.opNames[opName]
}
}
}
export default global
axios 拦截器设置 处理请求loading
import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
export type ICustomAxiosConfig = AxiosRequestConfig & {
opName?: string;
}
axios.interceptors.request.use(config => {
const newConfig = config as ICustomAxiosConfig
store.commit('setError', { status: false, message: ''})
store.commit('startLoading', { opName: newConfig.opName })
return config
})
axios.interceptors.response.use((resp: AxiosResponse<RespData>) => {
const { config, data } = resp
const newConfig = config as ICustomAxiosConfig
store.commit('finishLoading', { opName: newConfig.opName })
const { errno, message } = data
if (errno && errno !== 0) {
store.commit('setError', { status: true, message })
return Promise.reject(data)
}
return resp
}, (e: AxiosError) => {
const newConfig = e.config as ICustomAxiosConfig
store.commit('setError', { status: true, message: '服务器错误' })
store.commit('finishLoading', { opName: newConfig.opName })
return Promise.reject(e)
})
**### 注意: 需要在其他地方设置 opName 这个请求参数的 **
const newConfig = { ...config, data, opName: commitName }
const newConfig = { ...config, data, opName: commitName }
在项目中使用
const isLoading = computed(() => store.getters.isOpLoading('fetchTemplates'))
将全局错误和读取添加到跟组件
<template>
<div class="app-container">
<a-spin v-if="showLoading" tip="读取中" class="global-spinner"/>
<router-view/>
</div>
</template>
<script lang="ts">
import { defineComponent, computed, watch } from 'vue'
import { useStore } from 'vuex'
import { useRoute } from 'vue-router'
import { message } from 'ant-design-vue'
import { GlobalDataProps } from './store/index'
export default defineComponent({
name: 'App',
setup() {
const store = useStore<GlobalDataProps>()
const route = useRoute()
const isLoading = computed(() => store.getters.isLoading)
const showLoading = computed(() => isLoading.value && !route.meta.disableLoading)
const error = computed(() => store.state.global.error)
watch(() => error.value.status, (errorValue) => {
if (errorValue) {
message.error(error.value.message || '未知错误', 2)
}
})
return {
showLoading
}
}
})
</script>
<style>
.app-container .global-spinner {
position: fixed;
top: 10px;
right: 50%;
}
</style>