前端 File API

前端 File API本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。 在接触前端这么多年以来,发现对于 Web APIs 知识点的掌握,还是有很多模糊的地方,平时大部分情况都是使用第三方库或者百度 Google

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

在接触前端这么多年以来,发现对于 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;
}

代码地址: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 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 后,怎么显示缩略图

代码地址: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。

总结

我们应该要掌握 File 相关能力的基础知识,这样我们在处理文件相关的功能时能胸中有数,要想了解更多,可以去阅读文档,或者看一些优秀的库(如 exceljs,antd upload 组件等等)。

今天的文章前端 File API分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/18945.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注