在uniapp中,通常使用两个api实现本地图片选择和图片上传
- 本地图片选择
uni.chooseImage《chooseImage》文档地址 - 图片上传
uni.uploadFile《uploadFile》文档地址
问题引入:
1、
uploadFile是官方封装的,提供了一个回调函数参数 success来处理上传成功的情况。
2、上传是异步的,当有多图进行上传时,官方建议使用
循环遍历该api的方式来进行上传,但是由于封装过了,无法async await的方式来控制上传结果,特别是统一把握多图的上传情况,进行后续业务逻辑。
怎么解决:
1、本文提供了一种思路,使用
promise再次封装uni.uploadFile,最后使用promise.all来实现并发执行上传请求,并保持代码逻辑以同步方式顺序执行
2、使用
filter过滤请求结果,更加优雅
一、封装 uni.uploadFile为 promise
// ============= 防止异步,特地将《图片上传》封装成async await,在成功后调用 =================、
// 思考:不要做过多的提示,既然是封装,就应该让使用者知道,自己处理错误信息
const single_upload_promise = async (_filePath) => {
return new Promise((resolve, reject) => {
// --------- 上传图片到云端 ----------
uni.uploadFile({
url: import.meta.env.VITE_UPLOAD_BASEURL, // 从Vite的env中导入全局配置的上传地址,代码更优雅
filePath: _filePath,
name: "file",
// timeout: 30000, // 超时时间 30s
success: (uploadFileRes) => {
const res_upload = JSON.parse(uploadFileRes.data)
// -------这里举例 上传成功后,后端返回的json数据 ---------
// {
// "code":200,
// "msg":"上传成功",
// "time":"1745388478",
// "data":{
// "url":"\/1141\/uploads\/20250423\/3a452344109269b05a3e8800aefaa7be.jpg",
// "fullurl":"https:\/\/mkxy.oss-cn-shenzhen.aliyuncs.com\/1141\/uploads\/20250423\/3a452344109269b05a3e8800aefaa7be.jpg"
// }}
// ---- 接口报错 ----
if (res_upload.code != 200) {
reject(res_upload.msg) // 失败后,将错误信息返回给promis
return
}
// ---- 接口成功 ----
resolve(res_upload.data.fullurl) // 成功后,将图片url返回给promis
},
// ---- 请求失败 ----
fail: (err) => {
reject(err) // 失败后,将错误信息返回给promis
},
})
})
}
二、以promise.all实现并行上传,并控制代码为同步执行
// ============= 本地图片上传 =================
const handleUpload_LocalDCMI = () => {
// 打开相册选择图片
uni.chooseImage({
count: 9,
sizeType: ["original", "compressed"],
sourceType: ["album", "camera"],
success: async ({ tempFiles, tempFilePaths }) => {
// --------- 图片校验 ----------
let img_checked_flag = true // 图片校验通过标志 默认通过
const ALLOWED_EXTENSIONS = ["jpg", "jpeg", "png"]
for (let _file of tempFiles) {
const extension_end = _file.name.split(".").pop().toLowerCase()
if (!ALLOWED_EXTENSIONS.includes(extension_end)) {
toast.error(`不支持的文件类型:${_file.name}, 请选择JPG/PNG/JPEG格式`)
img_checked_flag = false // 图片校验不通过
return // 立即终止当前 handleUpload_LocalDCMI 函数的执行
}
}
// --------- 并行形式上传图片到oss ----------
// 实现并行上传所有图片,并await使得代码以同步的方式执行
let oss_urls = (
await Promise.all(
// 超屌处理
tempFilePaths.map((item) =>
single_upload_promise(item)
.then((res) => {
// 上传成功后,将图片url返回给promis
return res
})
.catch((err) => {
toast.error(`上传${item}失败:${err}`)
return false // 上传失败,返回 false,到时候过滤掉
}),
),
)
).filter(Boolean)
// --------- 上述代码是同步的,到这里已经全上传完了---------
console.log("用户所选的所有图,已上传到oss成功 oss_urls: ", oss_urls)
// 结果数据会变成这样: oss_urls = ["https://aaa.png","https://aaa.png","https://aaa.png"]
// ------------------- 后续业务逻辑处理 -------------------
if (
oss_urls.length > 0 ||
oss_urls.length == tempFilePaths.length
) {
// 上传成功
toast.success("全部上传成功")
} else {
// 上传失败
toast.error("部分上传成功")
}
// ......省略业务逻辑代码
},
})
}