文件上传及相关操作
文件上传及相关操作
1. 基础知识
数据传输到后端分为两种:
- 二级制blob传输:formDate传输
- base64传输:转为base64传输
相关对象:
- files:通过input标签过来的文件
- blob:二进制内容(不可变),包含众多操作方法
- formDate:用于与后端传输的对象
- fileReader:把文件读取为某种形式,如base64、text
注意:files本质是blob的子类,文件的断点上传、切片都是基于blob。
2. 文件处理
首先给定一个input标签,type属性值必须是file。
1 | <input type="file" name="file" @change="fileChange" /> |
接着开始对上传过来的文件进行相关处理。
2.1 文件属性限制
当你需要对文件的大小、类型做出限制时,可以直接抓取其对应属性。
1 | import { ElNotification } from 'element-plus'; |
2.2 文件相关操作
文件切割
在1.1提过相关基础知识,file其实本质是blob的子类。那么可以将上传的文件转化成二级制格式进行切割,接着再将切割后的对象转化为file。
1
2
3
4
5const fileChange = function(e){
let file = e.target.files[0];
let _sliceBlob = new Blob([file]).slice(0, 5000);
let _sliceFile = new File([_sliceBlob], "test.png");
}此时完成了文件的切割操作,当然实际没有这部分需求,可以省略。
格式转换
我们刚才介绍过文件传输到后端有多种格式,如果我们需要按照base64的格式进行传输,那可以进行以下操作。
1
2
3
4let fr = new FileReader();
fr.readAsDataURL(_sliceFile);
//读取文本
//fr.readAsText(_sliceFile);图片预览、截取
1
<img :src="imgbase64" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import { ref } from 'vue';
let imgbase64 = ref("");
const fileChange = function(e){
let file = e.target.files[0];
let _sliceBlob = new Blob([file]).slice(0, 5000);
let _sliceFile = new File([_sliceBlob], "test.png");
let fr = new FileReader();
//图片预览,只要再设置大小即可进行图片缩略
fr.readAsDataURL(file);
//图片截取
//fr.readAsDataURL(_sliceFile)
fr.onload = function(){
imgbase64.value = fr.result;
}
}这里我们也能发现,文本预览其实本质也一样,只不过是读取方式不一样。
1
fr.readAsText(file)
文件提交
文件传输形式其实跟Content-Type有关,主要为两种:
1. form表单,我们在表单中输入数据,如果不设置enctype,以默认application/x-www-form-urlencoded 方式提交数据;但通常表单上传文件会设置enctype,以multipart/form-data方式。1
2
3
4
5
6
7
8
9let _fileObj = ref({});
const fileChange = function(e){
_fileObj.value = e.target.files[0];
}
async submit(){
let _formData = new FormData();
_formData.append("file", _fileObj);
axios.post("/xx_url", _formData);
}- 以字符串形式,通过fileReader以base64或txt进行传递。
3. 实际操作
虽然标题是实际操作哈,但是前面展示的代码都可在实际中粘贴直接运行。
单文件上传前面已经提到了,2.2文件相关操作中文件提交就是单文件上传,非常简单。
3.1 多文件上传
很多教程都是说input标签直接加multiple即可,确实可以完成对应功能,但是用户体验感不好,需要进行优化。
1 | <input type="file" name="file" @change="fileChange" multiple/> |
这其实需要用户按住ctrl进行操作,但是用户更加偏向于一份份上传,所以可以进行改良。
1 | import { ref } from 'vue'; |
上传的时候直接遍历整个imgList,一份份文件上传即可。
1 | async submit(){ |
这里我们可以看出来,多文件上传本质就是循环的单文件上传。
3.2 切片上传
当文件体积过大时,可以使用切片上传,以2M为单位进行切片。
1 | let _fileObj = ref({}); |
3.3 断点续传
我实际没遇到过,这玩意实际应该是后端的活。本质就是切片上传中current存入缓存中,以便下次从current直接开始继续传输。
1 | loaclStorage.setItem(_fileObj.name, current); |
3.4 图片处理
图片本质也是文件的一种,所以上述文件的操作,图片皆可使用。但是图片上传存在与普通文件不同点,如图片压缩、剪裁等,现进行简要介绍一下概念。
图片压缩
思路为首先获取文件对象,转成base64,接着创建canvas对象,调用drawImage进行绘制(具体参数分别为对象、横纵坐标、长宽)。最后转化为blob/base64,进行压缩。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42<template>
<div>
<input type="file" name="file" @change="fileChange"/>
<img ref="img1" :src="imgbase64" />
</div>
</template>
<script setup>
import { ref } from 'vue';
let imgbase64 = ref("");
// 获取图片的真实DOM
let img1 = ref(null);
function fileChange(e){
// 读取
let file = e.target.files[0];
// 预览
let fr = new FileReader();
fr.readAsDataURL(file);
fr.onload = function(){
imgbase64.value = fr.result;
// VUE异步,也可以使用$nexttick
setTimeout(() => {
// 创建canvas对象,且是2d的
let pressCanvas = document.createElement("canvas");
pressCanvas.width = img1.value.width;
pressCanvas.height = img1.value.height;
let ctx = pressCanvas.getContext("2d");
// 绘制图片
ctx.drawImage(img1.value, 0, 0, img1.value.width, img1.value.height);
// 进行转换,blob还是base64
// 注意,转换对象得是真实DOM
// 参数说明:回调函数,转换类型,压缩值(0-1)
pressCanvas.toBlob((blob) => {
// 调用上传接口
let _formData = new FormData();
_formData.append("file", blob);
axios.post("/xx_url", _formData);
}, "image/jpeg", 0.6)
})
}
}
</script>截图保存
截图保存分为两种:
- 截取 图片DOM / canvasDOM / videoDOM,这种只要在绘制完成(drawImage),直接格式转换后直接filesaver即可;
- 截取页面上的DOM(div / document.body),则要使用 html2canvas;


