项目场景:在用户确定上传图片后手动开启上传任务,并在获取上传结束标志进行下一步操作。NutUI提供的上传组件<nut-uploader>支持自定义上传方式,删除已选图片且支持手动执行上传。
开启手动执行上传即可实现确定需要上传的图片后再上传oss服务器的功能,并自定义上传方法添加上传前的逻辑,如获取上传token。接下来需要在用户确认上传后获取上传结束标志并进行下一步操作,以上按官网文档配置上传方法:
<template>
<nut-uploader
:before-xhr-upload="beforeXhrUpload"
:auto-upload="false"
ref="uploadRef"
>
</nut-uploader>
</template>
<script setup>
import { ref } from 'vue';
// source file https://github.com/jdf2e/nutui/blob/v4/src/packages/__VUE/uploader/uploader.ts#L6
const beforeXhrUpload = (taroUploadFile, options) => {
//taroUploadFile 是 Taro.uploadFile , 你也可以自定义设置其它函数
const uploadTask = taroUploadFile({
url: options.url,
filePath: options.taroFilePath,
fileType: options.fileType,
header: {
'Content-Type': 'multipart/form-data',
...options.headers
}, //
formData: options.formData,
name: options.name,
success(response: { errMsg; statusCode; data }) {
if (options.xhrState == response.statusCode) {
options.onSuccess?.(response, options);
} else {
options.onFailure?.(response, options);
}
},
fail(e) {
options.onFailure?.(e, options);
}
});
options.onStart?.(options);
uploadTask.progress((res) => {
options.onProgress?.(res, options);
// console.log('上传进度', res.progress);
// console.log('已经上传的数据长度', res.totalBytesSent);
// console.log('预期需要上传的数据总长度', res.totalBytesExpectedToSend);
});
// uploadTask.abort(); // 取消上传任务
};
const uploadRef = ref(null)
const submitUpload = () => {
uploadRef.value.submit()
}
</script>
发现uploadRef.value.submit()没有定义回调函数,无法获得结束标志。查看该函数源码:
其中uploadQueuede的赋值代码:
UploaderTaro及其uploadTaro()方法:
不难看出submit()函数通过遍历uploadQueuede中的UploaderTaro对象的uploadTaro()方法依次执行上传任务,其中options.beforeXhrUpload(uploadFile,options)即为自定义的上传方式。
总体思路:由于上传图片不可避免地涉及异步操作,故考虑将submit()及其中所遍历的各个上传任务的改为异步操作,定义回调函数或使用await关键字获取结束标志。
实现细节:源码中使用foreach对上传任务进行遍历,而在 forEach 中使用 async/await 时,异步操作并不会等待前一个操作结束再执行下一个,而是会同时执行多个异步操作。若需要图片依次上传,需要使用for或while执行遍历。
而如果需要等待上传的图片同时上传,为了获取全部图片上传结束标志,需要将源码改为:
(不停摸索后的第一版成功的写法,比较冗杂...)
其他声明异步并等待的操作直接使用async/await关键字即可:
需要注意方法内部执行uploadTask上传的操作需要添加await关键字:
若此处使用自定义上传方法beforeXhrUpload()具体改法根据自定义内容而定,也切记在uploadTask.progress()方法前加await关键字!