答案:在请求的请求拦截中,开启loading。在请求返回的拦截中,关闭loading,为什么不生效了。
因为loading是在1s中后开启的。而请求由于时间比较快,可能就200ms,就想火车一样,你要拦截火车,此时火车还没有出发,你自然拦截不到,所有就无法关闭,等开启后,你拦截关闭,又没有执行这个命令,就跟响应式原理一样,没有在合适的时间执行关闭。这就是原因。
处理方式是加上定时器,在没有开启前,加上定时器,分为准备阶段,和运行阶段。
准备阶段,就销毁定时器,运行阶段,就隐藏loading。
let loadFlag
function startLoading() {
loadFlag = setTimeout(() => {
uni.showLoading({
title: '加载中',
mask: false,
});
}, 200);
}
function endLoading() {
clearTimeout(loadFlag)
if (loadFlag) {
uni.hideLoading()
}
}
// 那么 showFullScreenLoading() tryHideFullScreenLoading() 就是将同一时刻的请求合并。
// 声明一个变量 needLoadingRequestCount,每次调用showFullScreenLoading方法 needLoadingRequestCount + 1。
// 调用tryHideFullScreenLoading()方法,needLoadingRequestCount - 1。needLoadingRequestCount为 0 时,结束 loading。
let needLoadingRequestCount = 0
const showFullScreenLoading = function () {
if (needLoadingRequestCount === 0) {
startLoading()
}
needLoadingRequestCount++
}
const tryHideFullScreenLoading = function () {
if (needLoadingRequestCount <= 0) return
needLoadingRequestCount--
if (needLoadingRequestCount === 0) {
endLoading()
}
}
export {
startLoading,
endLoading,
showFullScreenLoading,
tryHideFullScreenLoading
}
在拦截的地方是这样的
// 此vm参数为页面的实例,可以通过它引用vuex中的变量
import { showFullScreenLoading, tryHideFullScreenLoading } from './loading'
module.exports = (vm) => {
// 初始化请求配置
uni.$u.http.setConfig((config) => {
console.log('config-res')
console.log(config)
/* config 为默认全局配置*/
config.timeout = 15000
// config.baseURL = 'http://101.133.133.5:3001/'; /* 测试服务器 */
// config.baseURL = 'https://dev.51xindata.com/xdr-gateway'; /* 开发服务器 */
config.baseURL = 'https://test.51xindata.com/xdr-gateway'; /* 测试服务器 */
// config.baseURL = 'https://51xindata.com/xdr-gateway'; /* 测试服务器 */
// config.baseURL = 'http://192.168.110.135:3001/' // 邱兴国
// config.baseURL = 'http://192.168.110.137:3001/'; //曾乐
// config.showLoading = true
// config.loadingTime = 800
// config.originalData = true
// config.loadingMask = true
return config
})
// let loading;
// 请求拦截
uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
showFullScreenLoading()
// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
config.data = config.data || {}
// 根据custom参数中配置的是否需要token,添加对应的请求头
if (config?.custom?.auth) {
// 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
// config.header.token = vm.$store.state.userInfo.token
// const token = 'Bearer ' + uni.getStorageSync('token');
const token = uni.getStorageSync('accessToken')
if (token) {
config.header.Authorization = 'Bearer ' + token;
}
}
return config
}, config => { // 可使用async await 做异步操作
tryHideFullScreenLoading()
return Promise.reject(config)
})
// 响应拦截
uni.$u.http.interceptors.response.use((response) => { /* 对响应成功做点什么 可使用async await 做异步操作*/
tryHideFullScreenLoading()
const data = response.data
// 自定义参数
const custom = response.config?.custom
if (data.code !== 200 && data.code !== 7001) {
// 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
if (custom.toast !== false) {
uni.$u.toast(data.message)
}
// 如果需要catch返回,则进行reject
if (custom?.catch) {
return Promise.reject(data)
} else {
// 否则返回一个pending中的promise,请求不会进入catch中
return new Promise(() => { })
}
} else if (data.code == 7001) {
// 假设401为token失效,这里跳转登录
uni.$u.toast('登录已过期,请重新登录')
setTimeout(() => {
// 此为uView的方法,详见路由相关文档
uni.removeStorageSync('accessToken')
uni.removeStorageSync('phoneRefreshToken')
uni.removeStorageSync('personalId')
uni.setStorageSync('isLogin', false);
uni.removeStorageSync('hostoryArr')
uni.setStorageSync('hostoryArr', ['/pages/index/index'])
uni.removeStorageSync('avatarUrl')
vm.$u.route('/pages/login/login')
}, 500)
return false;
} else {
return data.data === undefined ? {} : data.data
}
}, (response) => {
tryHideFullScreenLoading()
// 对响应错误做点什么 (statusCode !== 200)
return Promise.reject(response)
})
}