一.需求
- uniapp打包的H5项目,首页模块的业务逻辑偏多,调用的接口数量庞大,在弱网络的情况下切换了页面或者网络较好但是页面的UI未渲染完成的情况下快速地切换了页面会出现UI渲染错乱的问题,针对该问题个人从两个方面来进行处理;
- 切换页面时 取消对网络的请求 显示UI的渲染;保证首页渲染结束之前,限制底部tab的切换;
二.代码实现
2.1.网络请求框架选型
基于Uview的http进行的封装,主动取消网络需要借助下方getTask中的task;
封装的网络请求代码如下,包含两个js文件,httpRequest.js和service.js:
httpRequest.js
//httpRequest.js
// 引入基路径
import {
baseURL
} from "@/config/index.js"
// 此vm参数为Vue 实例 或 页面实例 ,可以通过它引用vuex中的变量
module.exports = (vm) => {
// 初始化请求配置
uni.$u.http.setConfig((config) => {
/* config 为默认全局配置*/
config.baseURL = baseURL
config.loadingText = '加载中...'
config.header = {
'Content-Type': 'application/json',
Authorization: Authorization
}
return config
})
// 请求拦截
uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
//根据需求自行改动======================================================
var token = uni.getStorageSync('access_token') || vm.vuex_token || null
if (config?.custom?.auth == undefined) {
if (token != null && token != '' && token != undefined) {
config.header["Authorization"] = "Bearer " + token;
} else {
vm.$u.toast("您尚未登录,请先登录");
uni.clearStorageSync();
setTimeout(() => {
//跳转到登录页面
}, 1500);
return false;
}
}
// 这一步就是给baseUrl重新赋值 !!!
if (config?.custom?.changeBaseUrl != undefined) {
config.baseURL = baseURL
}
// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
config.data = config.data || {}
if (config.data && config.data.header) {
config.header["content-type"] = config.data.header["content-type"];
}
//根据需求自行改动======================================================
return config
}, config => { // 可使用async await 做异步操作
return Promise.reject(config)
})
// 响应拦截
uni.$u.http.interceptors.response.use((response) => {
/* 对响应成功做点什么 可使用async await 做异步操作*/
const data = response.data
//根据需求自行改动======================================================
// 自定义参数
const custom = response.config?.custom
if (data.code !== 200) {
if (data.code == 401) { //token过期或者token为空
if (custom?.tokenExpire) {
return Promise.reject(data)
} else {
vm.$u.toast("您尚未登录,请先登录");
uni.clearStorageSync();
setTimeout(() => {
//跳转到登录页面
}, 1500);
return false;
}
} else if (data.code == 444) { //账号在其它位置登录
if (custom?.tokenExpire) {
return Promise.reject(data)
}
}
if (custom.toast !== false && data.msg != undefined && data.msg != '') {
uni.$u.toast(data.msg)
}
// 如果需要catch返回,则进行reject
if (custom?.catch) {
return Promise.reject(data)
} else {
// 否则返回一个pending中的promise,请求不会进入catch中
return new Promise(() => {})
}
}
//特殊处理
if (custom?.defaultStructure === true) {
return data === undefined ? {} : data
} else {
return data.data === undefined ? {} : data.data
}
//根据需求自行改动======================================================
}, (response) => {
// 对响应错误做点什么 (statusCode !== 200)
return Promise.reject(response)
})
}
- service.js
// 引入基路径
import {
baseURL
} from "@/config/index.js"
let baseInfo2 = "service/baseInfo"
export const baseInfo = (config = {}) => http.post(baseInfo2, config)
- 页面中逻辑,引入service文件,定义baseInfo方法,onHide声明周期方法中调用取消网络请求
async getBaseInfo() {
await baseInfo({
getTask: (task, options) => {
that.requestTask = task//定义变量
console.log("personInfo requestTask")
},
}).then((res) => {
//省略
//渲染UI逻辑
})
}
onHide() {
if (requestTask != null && requestTask.abort) {
requestTask.abort()
}
},
async onShow() {
await this.getBaseInfo()
uni.showTabBar(); // 显示底部 tabBar
},
2.2.保证首页渲染结束之前,限制底部tab的切换
onLoad() {
// 隐藏底部 tabBar
uni.hideTabBar();
},
三.总结
- 通过以上两个方面的处理,弱网络环境下出现的页面UI渲染错乱问题有个较好的解决。