1. 功能需求
在点击按钮请求接口的时候,不需要在处理函数内把loading改为true或false,而是识别请求的url,修改相对于loading的值。也就是说,当需要等待接口执行时,可以直接注册一个等待标志,而不是将流程内嵌到各种成功失败流程的处理代码中去。
2.大致思路
因为一个url对应一个loading,所以我希望能把这种对应关系存到一个数据里。新建一个waitHandleStore.ts文件,state里有loadingUrlObj,用于储存url和相对应loading的一一对应关系,声明两个方法,一个用于在请求拦截器和响应拦截器修改loading的值,一个用于往loadingUrlObj添加数据。
3.实现
3.1简化版
首先,state里声明loadingUrlObj,初始化为{};
往loadingUrlObj里添加数据:在组件文件里声明:btnLoding:fn(url),将url和btnLoading绑定起来,并且这个函数返回loading的状态。
在store文件里,fn(url)的实现写在这里。fn有两个功能:①往loadingUrlObj添加url和loading对应关系的数据;②返回当前url对应的loading的值。
在axios二次封装文件里,识别url,在请求拦截器里把相对应的loading值改为true,因为要包括错误处理,所以在请求的finally()里把loading改为false。
3.2详细版
waitHandleStore.ts里:
import { commonStoreShell } from '@/common/StoreShell';
import Vue from "vue";
import { CacherKeys } from "@/plugin/axios";
interface WaitHandleState {
loadingUrlObj: object,
}
interface WaitHandleGetters {
}
/**
* 此类专门用于提供各类等待标志,等待标的为特定接口
* 也就是说,当需要等待接口执行时,可以直接从这里注册一个等待标志,而不是将流程内嵌到各种成功失败流程的处理代码中去
* 因为等待是基于接口,故可以保证等待状态是正确的
*/
class WaitHandleStore extends commonStoreShell<WaitHandleState, WaitHandleGetters> {
public getters = {
}
protected getStateInit(): WaitHandleState {
return {
// 结构:loadingUrlObj: {
// '/url': {
// loading: true/false,
// seller: string //服务器名称
// }, ...
// }
loadingUrlObj: {},
}
}
// 修改url相对应loading的值
public setLoadingObjVal(key: string, newVal: boolean) {
this.state.loadingUrlObj[key].loading = newVal
}
// 新增url-loading,返回loading的值
public getLoadingFlag(sellerSlot: CacherKeys, url: string) {
if (!this.state.loadingUrlObj.hasOwnProperty(url)) {
Vue.set(this.state.loadingUrlObj, url, { loading: false, seller: sellerSlot });
}
return this.state.loadingUrlObj[url].loading
}
}
const waitHandle = new WaitHandleStore();
export { waitHandle };
axios二次封装文件里:
import { waitHandle } from '@/views/modules/waitHandleStore'
function createAxios(baseURL, cacherSlot: keyof typeof promiseCacher) {
const instance = axios.create({
baseURL,
timeout: 1000 * 180,
withCredentials: true
})
instance.interceptors.request.use(config => {
// 请求拦截器识别到请求的url有注册过且服务器一致,改url对应loading为true(开始加载)
if (waitHandle.state.loadingUrlObj.hasOwnProperty(config.url!) && cacherSlot === waitHandle.state.loadingUrlObj[config.url!].seller) {
waitHandle.setLoadingObjVal(config.url!, true)
}
// 其他操作......
return config
}, error => {
return Promise.reject(error)
})
instance.interceptors.response.use(response => {
// ......
return response.data;
}
}, error => {
errorLog(error.message)
return Promise.reject(error)
})
return {
request<T = any>(config: AxiosRequestConfig & catcherExtraConfig): AxiosPromise<T> {
const promise = instance.request(config).finally(() => {
// 无论请求是否抛出错误,把loading改为false(停止加载)
if (waitHandle.state.loadingUrlObj.hasOwnProperty(config.url!) && cacherSlot === waitHandle.state.loadingUrlObj[config.url!].seller) {
waitHandle.setLoadingObjVal(config.url!, false)
}
// 其他操作......
});
return promise;
},
}
}
// axios主实例
const { request: service } = createAxios(process.env.VUE_APP_API, 'main');
// axios副实例
const { request: service_b2b } = createAxios(process.env.VUE_APP_API_B2B, 'b2b');
// axios副实例
const { request: service_seller } = createAxios(process.env.VUE_APP_API_SELLER, 'seller');
export default service;
export { service, service_b2b, service_seller };
使用:vue文件里
<template>
<d2-container ref="container">
<el-button :loading="loadingFlag && selStatus" @click="disable()">{{ t('input_stop') }}</el-button>
<el-button :loading="loadingFlag && !selStatus" @click="enable()">{{ t('input_start') }}</el-button>
</d2-container>
</template>
<script>
import { waitHandle } from '../waitHandleStore'
export default {
computed: {
// 注册url-loading
loadingFlag() {
return waitHandle.getLoadingFlag('main', '/ProductItem/updateStatus')
},
},
};
</script>