Fork me on GitHub

前端文件上传下载

前端不时会碰到关于上传图片,下载Excel报表日志之类的业务需求,从原始的form表单提交到new formData()异步上传;从直接window.open(url)new blob()new fileReader()读取返回的二进制流文件。都让我们对文件处理更多的选择与操作,本文主要记录前端中关于文件的处理,包括上传下载及相关API。

文件上传

文件上传需要先调用读取本地文件API

获取文件方式

input方式

input[type='file' multiple]调用,multiple属性可以允许客户上传多个文件。获取该dom节点可以看到有个files属性(FileList对象),它对应文件列表,是一个类数组,这个列表中的每一个文件,就是一个 file 对象。

1
2
3
4
5
6
<input type='file' multiple />
<script>
document.querySelector('input').onchange = function(e) {
console.log(e.target.files);
};
</script>

tips:上传同个文件不触发onchange事件——每次上传之后重置input.value(上传文件路径)

drag方式

dom.ondrop事件获取e.dataTransfer.files(概念同上),dataTransfer指向一个对象,包含了与拖动相关的各种信息

1
2
3
4
5
6
7
8
9
10
<textarea></textarea>
<script>
const container = document.querySelector('textarea');
container.ondragover = function () { return false; };
container.ondrop = function(e) {
e.stopPropagation();
e.preventDefault();
console.log(e.dataTransfer.files);
};
</script>

file对象

通过用户交互获取到需要上传的文件,它的属性如下:
name:文件名
size:文件大小,单位为字节,可以根据文件大小来进行限制
type:文件的 MIME 类型,如果分辨不出类型,则为空字符串,可以由此来限制只允许上传图片
lastModified:文件的上次修改时间,格式为时间戳。
lastModifiedDate:文件的上次修改时间,格式为 Date 对象实例。

FileReader 对象

有时候我们需要读取文件的一些内容,例如预览图片;而FileReader对象就是用来把文件读入内存,并且读取文件中的数据接受 File 对象或 Blob 对象作为参数。

常规操作——按照需求方式读取文件并处理文件

1
2
3
4
5
reader.onload = function (ev) {
console.log(ev.target.result)
console.log(reader.result)
}
reader.readAs**方式**(file);

原始form表单提交方式

1
2
3
4
<form action="/saveFile" method="post" enctype="multipart/form-data">
<input type="file" name="fileName" />
<button type="submit">上传</button>
</form>

貌似也没啥问题,可是会刷新网页!这就尴尬了,很多情况下我们不想这样子,所以ajax提交来了。

ajax构建FormData提交

先来看看FormData——模拟form表单将数据编译成键值对,以便用XMLHttpRequest来发送数据

1
2
3
let FormData = new FormData();
FormData.append(name, file);
ajax(FormData)...

文件下载

传统下载

原理是直接访问网络资源地址,触发浏览器下载行为

  1. window.open(url)或iframe方式。iframe已被弃用,新建窗口打开资源文件方式会有一闪而过的现象,不大友好。
  2. a 标签的 download 属性

异步下载

原理是获取到文件后重新构造文件URL,访问下载。在这里需要了解一下blob

blob对象

上文中,File 对象便是是继承自 Blob 对象,Blob 对象代表了一段二进制数据,它有两个属性:size 属性表示字节长度,type 属性表示 MIME 类型。

1
let blob = new Blob(['hello blob'], {type:"text/plain"});

Blob 构造函数中的第一个参数是一个数组,可以存放 ArrayBuffer对象、ArrayBufferView 对象、Blob对象和字符串
此外还可以通过blob对象slice或canvas.toBlob()方式构造。

ajax文件下载

  1. 首先要理清responseType, 即返回类型,根据不同返回类型ajax去不同地方取返回值并做不同处理,如下:
    xhr.response:ArrayBuffer、Blob、Document,json
    xhr.responseText:DOMString(等同于默认设置responseType=’’)
    这里我们根据自身需求设置responseType

  2. 下载的文件处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 对返回的文件构造做兼容处理
    res = 'response' in xhr ? xhr.response : xhr.responseText
    let file = new Blob([res])

    // 创建a链接模拟点击下载
    downloadFile(file, name, type = 'xlsx') {
    let url = window.URL.createObjectURL(file)
    let link = document.createElement('a')
    link.style.display = 'none'
    link.href = url
    // 设置下载文件名
    link.setAttribute('download', `${name}.${type}`)
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    }