本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
在接触前端这么多年以来,发现对于 Web APIs 知识点的掌握,还是有很多模糊的地方,平时大部分情况都是使用第三方库或者百度 Google 复制粘贴一下,就实现了功能。所以在此想把基础夯实,好好学习下 Web APIs。
简介
本文将介绍 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;
}
原理是用 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 approximation
const 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 code
document.getElementById("fileNum").innerHTML = nFiles;
document.getElementById("fileSize").innerHTML = sOutput;
}
读取 size 后,利用循坏除于 1024 来判断文件的最大单位,最后根据这个来显示。
代码地址: codepen.io/wuzhengyan2…
拖拽图片显示缩略图
拖拽的能力也属于 Web APIs,可以阅读 HTML Drag & Drop API 指南 学习
我们这边只主要讲获取到 file 后,怎么显示缩略图
第一种为使用 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)
看下代码,就是构建 Blob 对象,在利用 createObjectURL 生成链接给 a 标签,最后调用下载能力。有兴趣的同学可以使用 File 对象试试,构建链接也可以使用 FileReader。
总结
我们应该要掌握 File 相关能力的基础知识,这样我们在处理文件相关的功能时能胸中有数,要想了解更多,可以去阅读文档,或者看一些优秀的库(如 exceljs,antd upload 组件等等)。
今天的文章前端 File API分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/18945.html