微信是不支持同时上传多张图片的,那要怎么优雅处理一次上传多张图片呢?
直接用场景入场吧:
商品订单的评论,一次可以对多个商品进行评论,每个商品又可以上传图片+视频,那怎么把这些需求放到一起统一处理?
-
商品
- 内容
- 图片 (需要先上传获取服务器临时地址,可以上传多张)
- 视频 (需要先上传获取服务器临时地址,只能最多一个视频)
-
商品
- 内容
- 图片
- 视频
-
商品
- 内容
- 图片
- 视频
-
提交数据
那就看一出好戏吧:
// 提交评论数据
submitAction(){
// 创建请求队列数组
var promiseAll = [];
// 判断是否对该订单评论了,有添加入队列中
for (let index = 0; index < this.data.commentModels.length; index++) {
// 组装请求队列
let request = this.requestUploadData(index)
promiseAll.push(request)
}
Promise.all(promiseAll).then((res)=>{
//所有请求完成了
console.log('完毕!!!')
setTimeout(() => {
wx.navigateBack()
}, 1500);
wx.showToast({
title: '评论已提交',
})
})
},
// 这是单个商品的评论内容+图片+视频
requestUploadData(index) {
let sectionVideos = this.data.sectionVideos
let sectionUploadImages = this.data.sectionUploadImages
const comment = this.data.commentModels[index];
var promiseAll = [];
if (sectionVideos[index]) { // 有视频
// 上传视频,获取成功之后的临时服务器视频地址,用于评论提交接口的视频参数
let request = requestPromise({
url: API.uploadFile,
filePaths: [sectionVideos[index]],
fileNames: ['multipartFile'],
data: {
type: 6
}
})
promiseAll.push(request)
}
// 有图片
let uploadImages = sectionUploadImages[index]
if (uploadImages && uploadImages.length > 0) {
let names = uploadImages.map((v)=>{return 'multipartFile'});
// 图片类似于视频的操作方式
let request = requestPromise({
url: API.uploadFile,
filePaths: uploadImages,
fileNames: names,
data: {
type: 3
}
})
promiseAll.push(request)
}
// 将数据组装成一个promise
return Promise.all(promiseAll).then(res => {
var data = {
...comment
}
res.forEach((v, i) => {
if (sectionVideos.length > 0 && i == 0) {
// 有视频路径
data['video'] = v[0]
} else {
// 图片路径
if (sectionVideos.length > 0) {
// 有视频的封面
data['videoImage'] = v.shift()['imagePath']
}
data['picturesList'] = v.map((value)=>value.imagePath)
}
})
// 提交单挑数据
return requestPromise({
url: API.orderComment,
method: 'POST',
data: data,
header:{'Content-Type':'application/json'},
})
})
},
这里第一次看,你会看到很多嵌套关系,而且看得有些云里雾里的。所以我做一个简单的说明
requestPromise: 这是封装好的数据请求类,包括图片上传,多张图片上传,其实调的是 wx.uploadFile
所有的请求都组装到 Promise 再做统一一次性的请求。
如果你理解了 Promise 使用方法,加上 Promise.all。 便不难理解上面的写法。
requestPromise 的封装代码如下
let ajaxTimes = 0;
/** 使用方式:
* requestPromise({
url:'url', // 必须的
data:data,
filePaths:[],
fileNames:[],
header:[:],
method:'GET',
hiddenLoading:false,
success:(orgRes)=>{
// 这里接收的是原始数据
}
}).then((result)=>{
// 这里接收的是data.data的数据
}).catch((error)=>{
})
*
*/
function requestPromise(params) {
// 判断 url中是否带有 /my/ 请求的是私有的路径 带上header token
var header = {
...params.header
};
var build = buildRequestHeader()
header = {
...build,
...header
}
ajaxTimes++;
// 显示加载中 效果
if (!params.hiddenLoading) {
wx.showLoading({
title: "加载中",
mask: true
});
}
// 定义公共的url
const baseUrl = getApp().globalData.httpHost;
return new Promise((resolve, reject) => {
var url = baseUrl + 'shop/' + params.url
// 上传文件
if (params.filePaths && params.filePaths.length > 0) {
// 是上传文件
var index = 0
var respDatas = []
function uploadImage(filePaths) {
wx.uploadFile({
filePath: filePaths[index],
name: params.fileNames ? params.fileNames[index] : 'file',
formData: params.data,
header: header,
url: url,
success (res){
let jsonData = JSON.parse(res.data)
const data = jsonData.data
respDatas.push(data)
index += 1
if (index == params.filePaths.length) {
resolve(respDatas);
// 关闭正在等待的图标
ajaxTimes--;
if (ajaxTimes === 0) {
// 关闭正在等待的图标
wx.hideLoading();
}
return;// 已经上传完了
}
uploadImage(filePaths)
}
})
}
uploadImage(params.filePaths)
return;
}
// 结束上传文件
wx.request({
...params,
header: header,
url: url,
success: (result) => {
if (result.data.code == 200) {
resolve(result.data.data);
if (params && params.success) {
params.success(result.data);
}
// 暂时不知道这里为什么会阻住之后的代码执行,只好先放在最后了
analysisResponseHeader(result.header)
} else if (result.data.code == 205) {
// 未登录需要重新登录
reject(result.data.msg);
let pages = getCurrentPages();
let page = pages.pop().route;
console.log(page)
if (page != 'pages/loginphone/index') {
wx.navigateTo({
url: '/pages/loginphone/index',
})
}
// 清空用户信息
wx.setStorageSync('serverIsLogin', false)
getApp().globalData.wxLoginCode = null
} else {
reject(result.data.msg);
var msg = result.data.msg ?? "";
if (msg.length > 6) {
if (msg.length > 100) {
msg = msg.substring(0, 100) + "...";
}
wx.showModal({
title: msg,
showCancel:false,
})
}else {
wx.showToast({
title: msg,
})
}
}
},
fail: (err) => {
reject(err.errMsg);
},
complete: () => {
ajaxTimes--;
if (ajaxTimes === 0) {
// 关闭正在等待的图标
wx.hideLoading();
}
}
});
})
}
// 解析响应头部信息来更新用户 sessionId
function analysisResponseHeader(header) {
var cookie = header["Cookie"]
if (!cookie) {
cookie = header["Set-Cookie"]
}
if (cookie && cookie.indexOf("sessionId=") >= 0) {
cookie = cookie.replace('sessionId=', '')
var iv = header["iv"]
var sessionId = signature.decrypt(cookie, iv)
if (sessionId) {
wx.setStorageSync('user_sessionId', sessionId)
}
}
}
// 组装请求头部信息
function buildRequestHeader() {
var header = {}
header["mini-version"] = getApp().globalData.mini_version
header["Content-Type"] = "application/x-www-form-urlencoded"
// User-Agent
var iv = signature.getIVTimestamp()
var sessionId = wx.getStorageSync('user_sessionId')
if (sessionId) {
var cookie = signature.encrypt(sessionId, iv)
header["Cookie"] = "sessionId=" + cookie
header["iv"] = iv
}
return header
}