目录
前端文件操作与文件上传
一、前端文件上传有两种思路:
- 二进制blob传输:典型案例是formData传输,相当于用formData搭载二进制的blob传给后端
- base64传输:转为base64传输,后端再将base64转回来。简便、耗时
二、与文件相关的对象
- files:通过input标签读过来的文件对象,是blob的子类。
- blob:不可变的二进制内容,包含很多操作方法,切片上传、断点续传都是基于blob的
- formData:用于后端传输的对象。files是一个前端的对象,不能直接传给后端,所以我们需要一个前后端都认可的载体来传递文件,这个载体就是formData。formData就像一辆汽车用来搭载files,这样才能让文件以二进制的形式传到后端
- fileReader:多用于把文件读取为某种形式(如base64、text文件)直接传给后端
三、file参数、blob切割文件、FileReader将文件转成base64,浓缩图/文本预览:
<template><div><inputtype="file"name="file"@change="fileChange"/><!-- 缩略图,文本预览 --><imgstyle="width:200px;":src="imgbase64"/><button@click="submit">提交</button></div></template><script>import axios from"axios"import{ fstat }from"fs";let _fileObj;exportdefault{name:'HelloWorld',data(){return{imgbase64:"",}},methods:{fileChange(e){let file = e.target.files[0]// files是个数组
_fileObj = file;// file常用属性:size(大小)、type(类型)、name(文件名)if(file.size >10*24*24){alert("文件不能大于十兆")}if(file.type !=='video/mp4'){alert("必须是mp4")}// 使用blob的slice方法可以切割文件let _sliceBlob =newBlob([file]).slice(0,5000);// 切割二进制的0-5000位// 将切割后的Blob对象转成File对象(第二个参数是文件名),之后就可以上传切割后的File对象let _sliceFile =newFile([_sliceBlob],"test.png");//将File对象或者Blob对象转成base64或textlet fr =newFileReader();
fr.readAsDataURL(_sliceFile);// readAsDataURL是转成base64的方法let self =this;
fr.onload=function(){// base64是异步的转换,通过onload方法获得转换结果
self.imgbase64 = fr.result// 直接将转换结果赋值给img的src,设置src的大小即可获得浓缩图
console.log(fr.result)// 打印结果见下图一}},asyncsubmit(){// 这部分的代码后面讲let _formData =newFormData();
_formData.append("user","asdasd");
_formData.append("file", _fileObj)
axios.post("/xx", _formData);}}}}</script>
四、formData:不仅可以搭载文件,还可以搭载文字、input的其他输入
<formaction="xxx"method="post">默认情况下提交为query参数</from><formaction="xxx"method="post"enctype="multipart/form-data">enctype指定提交为formData</from>
五、文件上传:将blob转成FormData上传
asyncsubmit(){let _formData =newFormData();
_formData.append("user","asdasd");
_formData.append("file", _fileObj)
axios.post("/xx", _formData);}
通过查看网络可以发现:
- 上传内容:
- 请求头content-Type指定了传输内容为form-data,且boundary指定了分割符
- 分隔了两个内容(下面还有一个分割线,即以分割线结尾) 六、转换关系
- 我们直接拿到的是file对象,file对象可以转换成Blob对象,Blob对象也可以转成file对象
- file、blob都可以根据FileReader读成base64或text文本
- 通过接口传输给后端时,只能传输base64、text文本、formData,所以,如果不把file、blob通过FileReader读成base64或text文本,那么就需要把file或者blob append到formData才能通过接口传输
七、具体功能
- 单文件上传(详见前述代码)
- 多文件上传:
<template><div><inputtype="file"name="file"@change="fileChange"multiple/><spanv-for="item in imgList">{{ item.name }}</span><button@click="submit">提交</button></div></template><script>import axios from"axios"import{ fstat }from"fs";let _fileObj;exportdefault{name:'HelloWorld',data(){return{imgList:[],}},methods:{fileChange(e){//多文件上传// multiple的多文件上传其实很不友好,需要用户在选择文件时按住ctrl多选,否则就会变成单选// 所以使用imgList数组将用户每次选择的内容都push进去if(e.target.files.length >1){this.imgList.concat(e.target.files)}else{this.imgList.push(e.target.files[0]);}//切片上传
_fileObj = e.target.files[0]},asyncsubmit(){// 遍历,一个一个上传this.imgList.forEach((item)=>{let _formData =newFormData();
_formData.append(item.name +"file", item)
axios.post("/xx", _formData);})}}}</script>
- 切片上传
<template><div><inputtype="file"name="file"@change="fileChange"multiple/><div>{{ precent }}%</div><button@click="submit">提交</button></div></template><script>import axios from"axios"import{ fstat }from"fs";let _fileObj;exportdefault{name:'HelloWorld',data(){return{precent:0}},methods:{fileChange(e){//切片上传,在上传的时候进行切片,文件改变时只赋值
_fileObj = e.target.files[0]},asyncsubmit(){let size =2*1024*1024;// 每次切片的大小,片为2mlet fileSize = _fileObj.size;let current =0;// 当前已经传了多少// 断点续传,永久记录中断的地方,下次上传时直接从断点开始传//localStorage.setItem(_fileObj.name, current);while(current < fileSize){let _formData =newFormData();
_formData.append(_fileObj.name, _fileObj.slice(current, current + size))await axios.post("http://localhost:4000/upload",_formData)// 进度条可以用axios的onUploadProgress方法,且发送切片时可以并行发送请求,后续可以自行优化this.precent = Math.min((current / fileSize)*100,100)
current += size;}}}}</script>
File System Access API 允许直接读取、写入或保存对用户设备上的文件和文件夹的更改。从 Chrome 86 开始支持 File System Access API,目前只有基于 Chromium 系列的浏览器全面支持,Safari 部分支持(支持读取,不支持写入和保存),而 Firefox 未支持。
前端接受后端传输文件指南
一、前端把后端传过来的文件下载下来(后端返回给我们的文件一般是二进制的),有以下几种方式:
- 直接打开下载地址:无法命名,只适用于get直接返回blob接口;没有通过项目去发,直接打开了一个窗口,相当于是浏览器请求的,就不会有token,无法做验证 直接在浏览器输入:
localhost:8000/download
就可以下载了,或者在代码中使用window.open(地址)
下载 - 利用a标签的download:比较合适的方案
几个重要的概念:
createObjectURL
:把blob对象的内存地址以URL形式给出。接口返回的是二进制传输的文件,那前端就可以拿到这个文件的blob对象,前端把这个blob对象传给createObjectURL
,得到一个URL,然后就可以使用a标签加载这个URL,从而实现下载msSaveBlob
:ie不支持a标签下载,用的是msSaveBlob
方案。如果是ie浏览器,直接调用msSaveBlob
方法,把blob对象给进去,就直接下载下来了- a标签的
download
属性:表面该a标签的行为时下载,并设置文件名
文件下载流程:
(1)
- file- saver:现成的库,简单方便
版权归原作者 CaraYQ 所有, 如有侵权,请联系我们删除。