最近有一个新需求,要求在前端实现真实的进度条展示,我首先想到了 Ant Design Vue的upload组件,在antd官网里upload组件不仅有上传功能,并且还附带了Progress 进度条组件,还拥有上传成功和失败的两种状态的区分,可以说是十分贴心了,如图
但是很可惜这个组件上传文件的话,你要在action里面指定你上传的路径,他会通过change函数传递你选择的文件列表而后自动把这个文件拿到并且上传到你给的地址中去,(也就是说你只需要给一个后端地址,其余的你选择了文件他就会帮你上传的)代码如下所示,
<template>
<a-upload-dragger
v-model:fileList="fileList"
name="file"
:multiple="true"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
@change="handleChange"
@drop="handleDrop"
>
<p class="ant-upload-drag-icon">
<inbox-outlined></inbox-outlined>
</p>
<p class="ant-upload-text">Click or drag file to this area to upload</p>
<p class="ant-upload-hint">
Support for a single or bulk upload. Strictly prohibit from uploading company data or other
band files
</p>
</a-upload-dragger>
</template>
<script lang="ts">
import { InboxOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { defineComponent, ref } from 'vue';
import type { UploadChangeParam } from 'ant-design-vue';
export default defineComponent({
components: {
InboxOutlined,
},
setup() {
const handleChange = (info: UploadChangeParam) => {
const status = info.file.status;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (status === 'done') {
message.success(`${info.file.name} file uploaded successfully.`);
} else if (status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
};
return {
handleChange,
fileList: ref([]),
handleDrop: (e: DragEvent) => {
console.log(e);
},
};
},
});
</script>
但是我这个项目里面不仅要求上传文件,同时还要传递一定的参数,那就不能像他这样直接给一个地址了,没办法只另辟蹊径了.上面说过其实antd 的upload组件里面也是包含的Progress 进度条组件,那这样的话我们刚好用它的Progress 组件就好了.
antd官网Progress组件示例
接下来就是具体的操作步骤了,其实也很简单
1.引入Progress并使用,同时给percent属性绑定一个uploadProgress的自定义值,这个percent属性其实就是进度条显示的百分比,设置100就是进度条全满,设置为0就是进度条为空.(进度条需要自己放在合适的位置)
2.调用函数,手动拿取文件并发送请求,如下图SystemImports函数其实就是一个请求函数,第一个参数就是后端需要的额外参数(这个不重要,属于我的项目的需求),第二个参数formData其实就是我们拿取到的文件并给他以formData的形式传给后端,也就是上传文件并获取这一过程(这个过程不懂得可以直接搜索js原生文件上传formData形式,我在这里就不过多赘述了)第三个参数也是最重要的参数,图中可以看到第三个参数是一个回调函数,我把这个回调函数接收到的参数(progressEvent)里的(loaded)属性和(total)进行处理后赋值给了uploadProgress.value,第一步里面percent属性绑定的值也就是进度条的进度刚好就是uploadProgress.value.也就是说我这里处理的其实就是进度条的实时进度.
3.那为什么我可以在直接拿到第三个参数回调函数的参数值progressEvent并且直接使用呢,这样就可以拿到实时进度了吗,其实关键就在下面这一步,如图这是我封装好的请求函数,这里有一个重要的属性就是onUploadProgress,我将第三个参数直接赋给他了,其实这样一来我们在上面请求函数里拿到的参数progressEvent就是该请求的一些实时信息,这个信息是会同步一直更新的 在你上传请求结束之前.
这是axios官网对onUploadProgress的解释
progressEvent就是获得的当前监控的上传信息,而progressEvent.loaded就是当前请求已发送数量,progressEvent.total就是当前请求应该发送的总数据数量,通过相应的处理自然可以知道当前处理进行到百分之几了,然后赋值给percent属性就可以了,所以到这一步基本上就可以像图片中那样处理进度条了,进度条也会实时变化了.
到了这里可能有些人试过之后发现,进度条确实变了 但是每次都是只变动一次,从0到100就结束了,这很有可能是因为上传速度过快,间隔过小导致的,建议开启浏览器调试,并切换到慢速3g上传一些较大的文件再次测试.当时我就能看到打印了许多个86的值,(第二步的图片里,我再处理函数里面打印了progressEvent)
以上步骤其实已经能够实时显示进度条了,其实还有一个问题需要处理,就是我们前端上传完毕了,但是后端还需要处理时间呀,那此时我们的上传进度是多少呢,是100%因为uploadProgress监控的是上传进度的完成,这就会造成我们进度条已经100%,但是后端仍需时间处理,最后导致返回滞后于进度条,那这样的话我们可以考虑给他加一个loading状态提示数据正在处理中,从而更好的提升用户体验.
各位大佬你们有什么对于实施进度条的新方法或者更合适的解决方案吗,求指导!!!