主要实现功能:单/多文件上传,分片上传,断点续传
两种方案:
二进制blob传输 使用formData传输
base64 把文件转为base64传输
传输的模式关系:file类实际上继承于Blob类,可以使用Blob的方法
搭建页面
使用input实现文件上传
<template>
<div>
<form actions="/xxx" method="post" enctype="multipart/form-data"></form>
<input
type="file"
ref="uploader"
name="file"
multiple
@change="filesChange($event)"
/>
<button @click="submits()">提交</button>
<br />
<img :src="imgUrl" style="width: 200px" alt="" />
<br />
<h3>上传进度{{ precent }}%</h3>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "myFile",
data() {
return {
imgUrl: "",
myfile: {},
fileList: [],
precent: 0,
};
},
};
</script>
<style lang="scss" scoped></style>
1.单文件上传
formData对象上的append(key,value)方法可以添加额外的参数,比如name,age等,
使用fileReader把选中的图片文件转为base64格式,设置img标签的src属性为这个转换后的base64格式的imgUrl,就可以实现回显功能,如果对文件使用slice方法进行切割,就只能回显图片的小部分内容
filesChange(e) {
//获取选择到的第一个文件
let file = e.target.files[0];
this.myfile = file;
if (file.size > 10 * 1024 * 1024) {
alert("文件最大为10MB");
}
if (file.type !== "image/jpeg") {
alert("图片格式必须是img");
}
//Blob对象使用slice方法来对文件进行裁剪,file也可以直接调用slice方法
//注意Blob和File两个类的相互转换,第一个参数必须在数组里面
let _sliceBlob = new Blob([file]).slice(0, 5000);
let _sliceFile = new File([_sliceBlob], "test.png");
let fr = new FileReader();
//转为base64格式,也可以使用fr.readAsText()转为文本
fr.readAsDataURL(file);
let self = this;
//转换方法是一个异步操作,后续操作必须使用fr.onload事件处理
fr.onload = function () {
self.imgUrl = fr.result;
};
//至此已经可以实现缩略图,和文本预览
},
async submit() {
let _formData = new FormData();
_formData.append("file", this.myfile);
_formData.append("user", "Zhang San");
axios.post("/xx", _formData);
},
注意:使用formDta传参必须给请求头需要为Content-Type:multipare/form-data
查看请求头的格式,分割线
浏览器会自动设置请求头Content-Type:multipare/form-data,不需要手动设置
请求的参数 如果想看传输的具体内容可以使用抓包工具进行抓包
2.多文件上传
使用fileList存储多个文件,如果上传的是多个文件就解构e.target.files并push到数组里面,如果是单个文件就直接push进数组,然后循环遍历数组发送请求即可
filesChange(e) {
//可以选取多个文件时
if (e.target.files.length > 1) {
//多个文件
this.fileList.push(...e.target.files);
} else {
//单个文件直接push就可以
this.fileList.push(e.target.files[0]);
this.myfile = e.target.files[0];
}
},
//多文件上传
async submits() {
this.fileList.forEach((item) => {
let _formData = new FormData();
_formData.append(item.name + "file", item);
_formData.append("user", "Zhang San");
axios.post("/xx", _formData);
});
},
3.分片上传,断点续传
filesChange(e) {
//以单个文件上传为例,可以改为多个文件
this.myfile = e.target.files[0];
},
//分片上传,断点续传,
async submits3() {
//限制单次传输的分片大小为2MB
let size = 2*1024*1024;
let fileSize = this.myfile.size;
let current = 0;
if (localStorage.getItem(this.myfile.name) !== null) {
current = localStorage.getItem(this.myfile.name);
}
while (current < fileSize) {
let _formData = new FormData();
_formData.append(
this.myfile.name,
this.myfile.slice(current, current + size)
);
try {
await axios.post("http://localhost:4000/upload", _formData);
this.precent = Math.min(
((current * 100) / fileSize) * 100 * 100,
100
);
current += size;
} catch (error) {
//如果出现异常情况,保存上次传输的current位置,并且设置key为文件名字,
//如果下次传输的文件相同,就采用current的上次保存的位置
localStorage.setItem(this.myfile.name, current);
}
}
},