> 文章列表 > 前端 File API

前端 File API

前端 File API

本文将介绍 File API,文件操作在 Web 有很多的应用场景,比如文件上传,导出数据为 Excel,导出 JSON 数据等等。

相信面对以上的场景,几乎所有人都会选择使用第三方库来实现。使用优秀的第三方库相对比自己实现更可靠,同时也更省时,一个小缺点就是库的有些能力你用不到,但是你还是要引入整个库,造成项目体积大小增加。

所以在确定使用的库功能不是很多的情况下,也可以尝试自己实现下。

接下来先介绍 Flie 相关的一些类,然后在通过一些常用的示例实践一下这些 API。

Web API 接口

Blob

Blob 对象表示一个不可变、原始数据的类文件对象。我们直接来看这么使用它:

const blob = new Blob(['hello world'], { type: 'text/plain' })
复制代码

第一个参数是个数组,数组项可以是 ArrayBuffer, String 等等,第二个是配置项,最常用的就是 type 属性,可以传入 text/plain, text/html 等

属性和方法 说明
size Blob 对象中所包含数据的大小(字节)
type 一个字符串,表明该 Blob 对象所包含数据的 MIME 类型
slice(start, end) 返回一个新的 Blob对象,包含了源 Blob 对象中指定范围内的数据。和字符串的 slice 方法类似
stream() 返回一个能读取 blob 内容的 ReadableStream
text() 返回一个 promise 且包含 blob 所有内容的UTF-8格式的字符串
arrayBuffer() 返回一个promise且包含blob所有内容的二进制格式的 ArrayBuffer
const blob = new Blob(['hello world'], { type: 'text/plain' })
blob.text().then(console.log) // 'hello world'
复制代码

File

文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容,继承了 Blob。

通常 File 对象来源有两个:

  • <input> 元素上选择文件后返回的 FileList 对象
  • 拖放操作生成的 DataTransfer 对象(dataTransfer.files)
const file = new File(["foo"], "foo.txt", {type: "text/plain",lastModified: Date.now()
})
复制代码

File 的构造函数和 Blob 有点类似,第一个参数是个数组,数组项可以是 ArrayBuffer, String 等等,第二个文件名称,第三个是配置项,支持 type 和 lastModified 属性,type 可以传入 text/plain, text/html 等,lastModified 默认为 Date.now()

File 除了 Blob 的方法和属性外,还有一些属性:

标题
lastModified 返回文件最后的修改时间,是个时间戳
lastModifiedDate 返回文件最后的修改时间,一个 Date 对象
name 文件名称
size 文件大小
webkitRelativePath 文件的本地路径或者 URL
type 文件的 MIME 类型
const file = new File(["foo"], "foo.txt", {type: "text/plain",lastModified: Date.now()
})
file.name // foo.txt
复制代码

FileList

FileList 就如它名称一样,类似一个 File 的数组,它只有一个方法

files.item(i) // 同 files[i]
复制代码

FileReader

FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,可以读取 Blob 和 File 的数据。

一个简单的使用例子,初始化后,监听 load 事件,然后调用读取方法。

const reader = new FileReader();
reader.onload = function(evt) {console.log(evt.target.result);
};
reader.readAsText(file)
复制代码
属性 说明
error 一个 DOMException,表示读取文件时发生的错误
readyState 0 代表还没加载,1 代表加载中,2 代表加载完成
result 文件的内容
事件 说明
onabort 读取操作被中断事件
onerror 读取操作发生错误的事件
onload 读取操作完成的事件
onloadstart 该事件在读取操作开始时触发
onloadend 该事件在读取操作结束时(要么成功,要么失败)触发
onprogress 读取 Blob 时触发
方法 说明
abort 中止读取
readAsArrayBuffer 开始读取数据,读取完后 result 是 ArrayBuffer 对象
readAsBinaryString 开始读取数据,读取完后 result 是二进制数据
readAsDataURL 开始读取数据,读取完后 result 是 Base64 字符串
readAsText 开始读取数据,读取完后 result 是字符串

URL

URL 是个很有用的对象,但是 IE 兼容性不好,这边主要介绍两个静态方法,其他内容可以查看 developer.mozilla.org/zh-CN/docs/…

两个静态方法如下:

  • createObjectURL() 返回一个字符串 ,包含一个唯一的blob链接(该链接协议为以blob:,后跟唯一标识浏览器中的对象的掩码)。

  • revokeObjectURL(),销毁之前使用 URL.createObjectURL() 方法创建的URL实例。

后续示例中我们来看具体使用

示例

隐藏的 file input 元素, 自定义上传按钮

默认的 input 标签的样式通常和 UI 设计稿的不同,所以我们需要自定义上传按钮的样式。

第一种我们可以通过 JS 来帮忙完成,直接看代码:

<input type="file" id="fileElem">
<button id="fileSelect">Select some files</button>
复制代码
#fileElem {display: none
}
复制代码
const fileSelect = document.getElementById("fileSelect"),fileElem = document.getElementById("fileElem");fileSelect.addEventListener("click", function (e) {if (fileElem) {fileElem.click();}
}, false)
复制代码

原理很简单,隐藏 input 标签,点击按钮后主动去触发 input 的 click 事件。

第二种是不使用 JS:

<div><input type="file" id="fileElem2" /><label for="fileElem2">Select some files</label>
</div>
复制代码
#fileElem2 {position: absolute;height: 1px;width: 1px;overflow: hidden;
}
复制代码

代码地址:codepen.io/wuzhengyan2…

原理是用 label 的 for 属性,for 属性和 input 的 id 对应时,点击 lable 就如同点击了 input。所以我们只有编写 label 的样式。

显示文件大小

显示文件大小就要使用到文件的 size 属性,我看下示例关键代码(本例子来子 MDN)

function updateSize() {let nBytes = 0,oFiles = document.getElementById("uploadInput").files,nFiles = oFiles.length;for (let nFileId = 0; nFileId < nFiles; nFileId++) {nBytes += oFiles[nFileId].size;}let sOutput = nBytes + " bytes";// optional code for multiples approximationconst aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];for (nMultiple = 0, nApprox = nBytes / 1024; nApprox > 1; nApprox /= 1024, nMultiple++) {sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)";}// end of optional codedocument.getElementById("fileNum").innerHTML = nFiles;document.getElementById("fileSize").innerHTML = sOutput;
}
复制代码

读取 size 后,利用循坏除于 1024 来判断文件的最大单位,最后根据这个来显示。

代码地址: codepen.io/wuzhengyan2…

拖拽图片显示缩略图

拖拽的能力也属于 Web APIs,可以阅读 HTML Drag & Drop API 指南 学习

我们这边只主要讲获取到 file 后,怎么显示缩略图

代码地址:codepen.io/wuzhengyan2…

第一种为使用 FileReader,调用 readAsDataURL 方法,就可以得到 base64 的字符串,直接赋值给 img。

// FileReader
const image = new Image()
const reader = new FileReader()
reader.onload = (e) => { image.src = e.target.result }
reader.readAsDataURL(file)
复制代码

第二种是使用 URL 的静态方法 createObjectURL。这个方法很简单直接,记得销毁即可。兼容性上看 FileReader 好些,具体可以查看 caniuse

const image = new Image()
image.src = window.URL.createObjectURL(file);
image.onload = function () {window.URL.revokeObjectURL(this.src);
}
复制代码

保存为 JSON 文件

保存为 JSON 文件这个示例我们使用 Blob 来完成

const text = {hello: "world"}
const blob = new Blob([JSON.stringify(text, null, 2)], {type : 'application/json'});
const link = URL.createObjectURL(blob)
const a = document.createElement('a')
document.body.appendChild(a)
a.download = 'data.json'
a.href = link
a.click()
document.body.removeChild(a)
复制代码

代码地址:codepen.io/wuzhengyan2…

看下代码,就是构建 Blob 对象,在利用 createObjectURL 生成链接给 a 标签,最后调用下载能力。有兴趣的同学可以使用 File 对象试试,构建链接也可以使用 FileReader。

作者:晓得迷路了
链接:https://juejin.cn/post/7022528039678377992
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

太原家教网