html和files同时操作,「HTML5」FileAPI 文件操作实战

本文来自《FileAPI 文件操作实战》

其他所有系列都放在了Github。欢迎交流和Star。

介绍

HTML5 为我们提供了 File API 相关规范。主要涉及 File 接口 和 FileReader 对象 。

本文整理了兼容性检测、文件选择、属性读取、文件读取、进度监控、大文件分片上传以及拖拽上传等开发中常见的前端文件操作。

准备工作

首先,我们的 File 来自于标签中选中的文件列表。所以,准备如下的 HTML 代码:

检测兼容性

File 对象是特殊类型的 Blob。在 script 入口处,应该检测当前浏览器是否支持 File API:

if (!(window.File && window.FileReader && window.FileList && window.Blob)) {

throw new Error("当前浏览器对FileAPI的支持不完善");

}

监听文件选择

对于 type 为 file 类型的标签,在选择文件的时候,会触发change事件。用户选中的文件信息也会传入回调函数的第一个参数中。

function handleFileSelect(event) {

const { files } = event.target;

if (!files.length) {

console.log("没有选择文件");

return;

}

console.log("选中的文件信息是:", files);

}

document

.querySelector("#files")

.addEventListener("change", handleFileSelect, false);

文件属性-File

event.target.files 是一个FileList对象,它是一个由File对象组成的列表。

每个 File 对象,保存着选中的对应文件的属性。常用的用:

name:文件名

type:文件类型

size:文件大小

下面,通过 type 属性,过滤掉非图片类型的文件,只展示图片类型文件的信息:

function handleFileSelect(event) {

const { files } = event.target;

if (!files.length) {

console.log("没有选择文件");

return;

}

const innerHTML = [];

const reImage = /image.*/;

for (let file of files) {

if (!reImage.test(file.type)) {

continue;

}

innerHTML.push(

`

${file.name}

(${file.type || "n/a"}) -${file.size}bytes

`

);

}

document.querySelector("#list").innerHTML = `

  • ${innerHTML.join("")}
`;

}

读取文件-FileReader

还是以图片读取为例,读取并且显示所有的图片类型文件。

文件读取需要使用FileReader对象,它常用 3 个回调方法:

onload: 文件读取完成

onloadstart:文件上传开始

onprogress : 文件上传中触发

和Image类似,在读取文件之前,需要先绑定事件处理。它读取操作有:readAsArrayBuffer、readAsDataURL、readAsBinaryString、readAsText。传入的参数就是File对象。

那么这几个方法有什么区别呢?不同的读取方式,回调事件onload接受到的event.target.result不相同。比如,readAsDataURL读取的话,result 是一个图片的 url。

下面就是读取图片文件,然后展示的一个例子:

function handleFileSelect(event) {

let { files } = event.target;

if (!files.length) {

return;

}

let vm = document.createDocumentFragment(),

re = /image.*/,

loaded = 0, // 完成加载的图片数量

total = 0; // 总共图片数量

// 统计image文件数量

for (let file of files) {

re.test(file.type) && total++;

}

// onloadstart回调

const handleLoadStart = (ev, file) =>

console.log(`>>> Start load${file.name}`);

// onload回调

const handleOnload = (ev, file) => {

console.log(`<<< End load${file.name}`);

const img = document.createElement("img");

img.height = 250;

img.width = 250;

img.src = ev.target.result;

vm.appendChild(img);

// 完成加载后,将其放入dom元素中

if (++loaded === total) {

document.querySelector("#images").appendChild(vm);

}

};

for (let file of files) {

if (!re.test(file.type)) {

continue;

}

const reader = new FileReader();

reader.onloadstart = ev => handleLoadStart(ev, file);

reader.onload = ev => handleOnload(ev, file);

// 读取文件对象

reader.readAsDataURL(file);

}

}

document

.querySelector("#files")

.addEventListener("change", handleFileSelect, false);

监控读取进度

在监控读取进度的时候,主要是处理 FileReader 对象上的 onprogress 事件。

下面的例子,请打开一个较大的文件来查看效果(否则一下就读取完了):

function handleFileSelect(event) {

let { files } = event.target;

if (!files.length) {

return;

}

const handleLoadStart = (ev, file) =>

console.log(`>>> Start load${file.name}`);

const handleProgress = (ev, file) => {

if (!ev.lengthComputable) {

return;

}

// 计算进度,并且以百分比形式展示

const percent = Math.round((ev.loaded / ev.total) * 100);

console.log(`<<< Loding${file.name}, progress is${percent}%`);

};

for (let file of files) {

const reader = new FileReader();

reader.onloadstart = ev => handleLoadStart(ev, file);

reader.onprogress = ev => handleProgress(ev, file);

reader.readAsArrayBuffer(file);

}

}

document

.querySelector("#files")

.addEventListener("change", handleFileSelect, false);

大文件分片读取

在对于超大文件,一般采用分片上传的思路解决。文章开头有讲到,File 是 Blob 的一个特例。而 Blob 上有一个slice 方法,通过它,前端就可以实现分片读取大文件的操作。

为了方便说明,请先准备好一个 txt 文件,文件内容就是:hello world。

示例代码如下,代码中只读取前 5 个字节,由于每个英文字母占 1 个字节,所以打印结果应该是“hello”。

function handleFileSelect(event) {

let { files } = event.target;

if (!files.length) {

return;

}

// 为了方便说明,这里仅仅读取第一个文件

const file = files[0];

// 读取前5个字节的内容

const blob = file.slice(0, 5);

const reader = new FileReader();

// 控制台输出结果应该是:hello

reader.onload = ev => console.log(ev.target.result);

reader.readAsText(blob);

}

document

.querySelector("#files")

.addEventListener("change", handleFileSelect, false);

拖拽上传

和前面所述的 File API 相关是完全一样的。唯一需要特殊处理的是文件对象的获取入口改变了。对于标签,监听 onchange 事件,FileList 存放在 event.target.files 中;对于拖拽操作,FileList 存放在拖拽事件的回调函数参数里,通过 event.dataTransfer.files 访问即可。

需要修改一下 html 代码:

width: 300px;

height: 300px;

border: 3px dotted red;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值