遇到这样一个业务场景,在小程序中 wx.chooseImage
选择图片后,
调用 wx.uploadFile
上传图片到公司的一个数据库中,然后拿到对应的返回值后,
再去请求一个接口,将所有图片一一进行绑定,
等所有图片上传完毕后,最后请求一个接口进行总结汇报。
我们希望的是当选择图片完成后,有一个loading加载中的效果,
然后等所有图片上传完毕并一一绑定,且最后一个总结汇报的接口也请求完毕后,
再隐藏loading弹窗,展示“上传完毕”。
听起来很简单的一个事情,但是我却踩坑了。
先看下大体的代码结构…
// 当前索引值
let i = 0;
// 需要上传的图片总数
let picNum = 0;
// 需要上传的图片路径
let picFilePaths;
// 选择图片
choosePic: function () {
const self = this;
wx.chooseImage({
count: 9,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
// 小程序API的限制 文件不能大于20M
if (res.size > 20971520) {
wx.showModal({
title: '上传失败',
content: '您选择的图片过大,请重新选择',
showCancel: false,
confirmText: '我知道了',
success: (res) => {
if (res.confirm) {
// 自定义的向外抛reload事件
self.triggerEvent('reload');
}
}
});
return;
}
this.uploadPic(res.tempFilePaths);
}
});
},
// 上传图片
uploadPic: function (tempFilePath) {
const self = this;
wx.showLoading({
title: '加载中...',
})
// 如果是数组说明正在上传多张图片
if (Array.isArray(tempFilePath)) {
// 上传的图片数量
picNum = tempFilePath.length;
// 上传的所有图片
picFilePaths = tempFilePath;
// 正在上传的图片
tempFilePath = picFilePaths[i];
}
wx.uploadFile({
url: '...',
filePath: tempFilePath,
name: '...',
formData: {
...
},
success: (res) => {
// 上传文件大于20M会返回413状态码
if (res.statusCode == 413) {
wx.showModal({
title: '上传失败',
content: '上传的图片文件过大,请重新选择',
showCancel: false,
confirmText: '我知道了',
success: (res) => {
if (res.confirm) {
self.triggerEvent('reload');
}
}
});
return;
}
const resData = JSON.parse(res.data);
// 取resData中的值
...
wx.request({
url: '...',
method: 'POST',
data: {
...
},
...
})
},
fail: (err) => {
wx.hideLoading();
wx.showToast({
title: err,
icon: 'none'
});
},
complete: () => {
if (picNum) {
i++;
if (i < picNum) {
self.uploadPic(picFilePaths);
} else {
...
// 请求成功后重新加载数据
self.triggerEvent('reload');
// 清空正在上传的图片张数
i = 0;
// 清空需要上传的图片总数
picNum = 0;
})
}
}
});
}
刚开始以为 wx.uploadFile
会自动给加个loading的弹窗,所以把这个请求直接屏蔽掉,发现还是有loading弹窗。
然后再看了下自己写的组件里 self.triggerEvent('reload');
发现都不沾边,只有失败或者最后一个请求成功后才会触发。
接着排查到wx.request
,因为看到我公司的一个封装的wx.request
方法中只有 wx.hideLoading
而没有 wx.showLoading
。
好叭,这个挺误导人的,让我以为 wx.request
会自带 wx.showLoading
所以这个封装里才只有 wx.hideLoading
。
但是后来越想越不对劲,明明官方文档里的 wx.request
请求前后的loading弹窗显示隐藏是需要我们自己去加的。
ok ~ 思路就聚焦到了 wx.chooseImage
这里是不是有问题,莫非选择图片完了会自动重新加载??
然后尝试着多加几个 wx.hideLoading
,我当时的脑回路也真是奇葩,最后的结果是没有效果,还是会选择图片完就有个loading。
直到最后我看到网上有個人说 wx.chooseImage
后会触发 app.onShow 方法 (此刻空气突然静止… )
然后我迅速找到这个页面的 onShow 方法,发现有个reload重新加载数据的逻辑,而加载数据时有个 wx.showLoading
。
所以这就造成了我选择图片并上传后出现两次loading弹窗提示…
第一个短暂的loading弹窗提示是onShow中reload重新加载数据时的showLoading。
而第二个loading弹窗才是我上传图片时加的showLoading。