文件上传的相关概念和使用

最近需要做上传组件,就整体梳理了一下文件上传的相关概念和使用。

唯一文件类型说明符和 MIME 类型

首先,实现上传的是 <input type="file">file 类型的 input 有一个属性 accept,用于限制可接受的文件类型。accept 属性的值,是一个逗号分隔的 唯一文件类型说明符 列表的字符串。

唯一文件类型说明符 的形式有:

  • 以英文句号开头的文件名扩展名,如 .png
  • MIME 类型 字符串

MIME 类型 是一种用来表示文档、文件等的性质和格式的标准,通用结构是 type/subtype,常见的例如 text/htmlimage/pngvideo/* 等( video/* 表示 “任何视频文件”)。

🌰
接受 XLSX 文件和任何图片文件:

<input type="file" accept=".xlsx, image/*">

File

file 类型的 input 还有一个属性是 files,它的值是一个 fileList 对象,用来存储用户所选择的文件,而每个文件就是一个 File 对象,可以获取有关文件的信息。

File 对象常用的属性有3个:

  • name —— 本地文件系统中的文件名
  • size —— 文件的字节大小
  • type —— 文件的 MIME 类型

🌰

document.querySelector('input').onchange = (e) => {
	const fileList = e.target.files;
	const file = fileList[0];
	
	console.log(fileList);
	console.log('name:', file.name);
	console.log('size:', file.size);
	console.log('type:', file.type);
}

File

Blob

Blob 是一个包含只读原始数据的类文件对象。File 类型是 Blob 的子类型,继承了 Blob 的功能并且扩展支持了用户系统上的文件。上述的属性中,sizetype 就是继承自 Blob

接受 Blob 对象的 API 也接受 File 对象,比如 FileReaderXMLHttpRequest.send() 等,都能处理 BlobFile

🌰

document.querySelector('input').onchange = (e) => {
	const fileList = e.target.files;
	const file = fileList[0];
	
	console.log(file instanceof File);  // true
	console.log(file instanceof Blob);  // true
}

🌰

const array = ['<div>hello</div>'];
const options = { type: 'text/html' };
new Blob(array, options);

Blob

进度事件

这些事件最早其实只针对 XHR 操作,但目前也被其他 API 借鉴。有以下 6 个进度事件:

  • loadstart —— 在接收到响应数据的第一个字节时触发
  • progress —— 在接收响应期间,每过 50ms 左右触发一次。event 属性:
    • lengthComputable —— 进度信息是否可用。false 表示总字节数是未知并且 total 的值为零
    • loaded —— 已经接收的字节数
    • total —— 根据 Content-Length 响应头部确定的预期字节数
  • error —— 在请求发生错误时触发
  • abort —— 在因为调用 abort() 方法而终止连接时触发
  • load —— 在接收到完整的响应数据时触发
  • loadend —— 在触发 errorabortload 事件后触发

FileReader

FileReader 让 Web 应用程序可以异步读取用户系统的文件内容。

常见的方法有:

  • readAsText(file[, encoding]) —— 以纯文本形式读取文件,将读取到的文本保存在 result 属性中。第二个参数用于指定编码类型
  • readAsDataURL(file) —— 读取文件并将文件以 data: URL 格式的字符串(base64编码)保存在 result 属性中
  • readAsArrayBuffer(file) —— 读取文件并将一个包含文件内容的 ArrayBuffer 保存在 result 属性中
  • abort() —— 中断读取过程

常用的事件为上述 进度事件。其中,触发 error 事件时,可以在 event.target.error 中获取到错误信息 { code: 1 | 2 | 3 | 4 | 5 },各数值的含义为:

  • 1 —— 未找到文件
  • 2 —— 安全性错误
  • 3 —— 读取中断
  • 4 —— 文件不可读
  • 5 —— 编码错误

🌰
获取图片文件的 base64:

document.querySelector('input').onchange = (e) => {
	const fileList = e.target.files;
	const file = fileList[0];
	
	if (file.type === 'image/png') {
		const reader = new FileReader();
	    reader.readAsDataURL(file);
	    reader.onload = (event) => {
			console.log('base64:', event.target.result);
	    };
	}
}

base64

XMLHttpRequest

XMLHttpRequest 对象用于与服务器交互。

常用的属性有:

  • upload —— 返回一个 XMLHttpRequestUpload 对象,用来表示上传的进度
  • readyState —— 请求的状态码,值为 4 表示请求已完成
  • status —— 数字形式的 HTTP 状态码,值为 2xx 表示用户请求被正确接收、理解和处理
  • responseText —— 字符串形式的响应数据
  • response —— 整个响应实体

常用的方法有:

  • open(method, url[, async]) —— 初始化一个请求
  • send(body) —— 发送请求
  • abort() —— 中止请求
  • setRequestHeader() —— 设置 HTTP 请求头的值。必须在 open() 之后、send() 之前调用

常用的事件为上述 进度事件,再加上一个 readystatechange,在 readyState 属性变化时触发。

load 事件替代了 readystatechange 事件,也不用检查 readyState 属性了。但需要检查 status 属性来确定数据是否可用。

常在 upload 属性上绑定 onprogress 事件来实现文件上传的进度条。为什么没有直接在 XMLHttpRequest 对象上绑定该事件呢?因为上传和下载都会触发 XMLHttpRequest 对象上的 progress 事件,而只有上传会触发 upload 属性上的 progress 事件。

FormData

如果直接传递文件内容,那么服务器端还需要收集提交的内容,再把它们保存到另一个文件中。所以需要以表单提交的方式来上传文件,即使用 FormData 上传文件,服务器端就会像接收常规表单数据一样正常处理。

FormData 是 XMLHttpRequest 2级 定义的类型,用 append() 方法向其中添加新的键值对。

🌰
文件上传:

const handleUpload = (file) => {
	const xhr = new XMLHttpRequest();
	const formData = new FormData();
	formData.append('file', file);
	xhr.upload.onprogress = (e) => {
		if (e.lengthComputable) {
			console.log('进度:', e.loaded / e.total);
		}
	};
	xhr.onerror = (e) => {
		console.log('error:', e);
	};
	xhr.open('post', 'https://www.mocky.io/v2/5cc8019d300000980a055e76');
	xhr.send(formData);
};

document.querySelector('input').onchange = (e) => {
	const fileList = e.target.files;
	const file = fileList[0];
	
	handleUpload(file);
}

进度
error

参考

MDN
《JavaScript高级程序设计》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值