一. 文件下载
(1) blob对象(以blob对象接收文件流)
- 模板文件下载: 以vue项目为例,模板文件放置public目录下,
axios({
url: 'xxxxx', // URL, 根据实际情况来 , 一般为‘应用包部署的baseUrl(即publicPath) + 模板文件路径’
method: "get",
responseType: "blob"
})
// 使用a标签承载下载功能
const blob = new Blob([data], { type: 'xxxxx' });
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, filename);
} else {
const href = URL.createObjectURL(blob); // 创建新的URL表示指定的blob对象(为生成的 URL 存储了一个 URL → Blob 映射)
const a = document.createElement('a');
a.style.display = 'none';
a.href = href;
a.download = filename;
a.click();
URL.revokeObjectURL(a.href); // 释放URL对象, 防止内存泄漏
}
(2) a标签download(后端直接返回url地址)
// 文件下载, 文件名展示,a标签download下载
<a :download="name" :href="url"> // 不支持跨域链接
// 图片下载(也适用于抓图场景)
// a标签download下载的内容浏览器可以识别时(img, .pdf等),会直接预览的效果,需转换为blob对象阻止浏览器直接解析
fetch(url).then((res) => res.blob()).then((blob) => {
// 使用a标签承载下载功能
// ...
})
(3) Base64下载
类似于blob下载
// 使用filReader + readAsDataURL, 读取为base64编码后的`url`形式
if (xxxx) {
const fileReader = new FileReader();
fileReader.readAsDataURL(respObj);
fileReader.onload = function () {
const a = document.createElement('a');
a.style.display = 'none';
a.href = this.result;
a.download = name;
document.body.appendChild(a);
a.click(); document.body.removeChild(a);
};
}
(4) window.open/location.href
二. 文件上传, 预览
- 普通上传
(1) formData上传 + blob对象预览: 不兼容h5
// 上传
const fd = new FormData();
// ...
axios({
url: "xxxxxx",
method: "post",
headers: { "Content-Type": "multipart/form-data" },
data: fd
});
// 使用对象url进行预览, 格式为“blob:<origin>/<uuid>”, 即blob协议url
const url = URL.createObjectURL(data);
<a :download="name" :href="url">
(2) base64上传 + Data Url预览: 使用filReader+readAsDataURL,兼容h5
// 上传
let fr = new FileReader();
fr.onload = function (e) {
that.imgBaseSrc = e.target.result;
//上传后台
// ...
};
// 一般图片使用Data Url形式读取(fr.readAsDataURL), 文件使用二进制数据流形式读取(fr.readAsBinaryString)
fr.readAsDataURL(file.files[0]);
/**
* 预览, Web性能优化有一项措施:把小图片用base64编码直接嵌入到HTML文件中,实际就是利用
* 了Data URL来获取图片数据
*/
src格式为:‘data:image/jpeg:base64,xxxxxx’
<img :src="imgBaseSrc">
Data Url和Blob Url的区别
- 前者用于小图片展示,后者用于大图片展示
- 前者移植性较好,可以在任何浏览器中使用,后者只能在当前应用使用
- Blob URL可以方便的使用xhr对象获取源数据
文件超大上传问题: 切片上传结合断点续传
核心点:切片上传、断点续传、进度管控
核心思路:
1.生成文件的唯一标识(获取已上传的切片数据)
2.将file对象进行切片, 分段进行上传操作
3.上传过程中进行进度管控(基于xhr.upload.onprogress事件)
详细代码参考: js管理大文件上传及断点续传解析
注意:实际开发过程中服务端会限制上传的文件大小(例如20M), 前端再上传之前会进行压缩、加水印等操作
// watermark + Compressor + fetch
watermark([img])
.image(xxx)
.then((imgRes) => fetch(imgRes.src))
.then((resp) => resp.blob())
.then((blob) => {
// 压缩
const fileWM = new File([blob], xxx);
return new Compressor(fileWM, {
quality: 0.8,
maxWidth: 1000,
maxHeight: 1000,
convertTypes: ['image/png', 'image/jpeg'],
convertSize: 50000,
,,,
});
});
三. 数据批量导入
以导入excel数据为例 核心思路:以二进制数据流形式读取,将二进制文件流解析为xlsx对象,读取excel工作表数据转化为json数据 使用技术点:XLSX, readAsBinaryString, FileReader
let fr = new FileReader();
fr.onload = function (e) {
const data = e.target.result;
const wb = XLSX.read(data, { type: 'binary' });
// 读取工作表数据转化为json数据
xxxxxx
};
fr.readAsBinaryString(file.files[0]);
// readAsBinaryString, 按字节读取,读取二进制数据并编码为字符串
// readAsArrayBuffer, 按字节读取,读取二进制数据为ArrayBuffer对象
四. 数据批量导出
类似文件下载功能:blob对象实现即时下载
五. 页面截图
核心思路:
- 使用 canvas.drawImage 在 canvas 上绘制图像
- 调用 canvas 方法 .toBlob创建一个 Blob,实现即时下载 也可以借助 html2canvas 库实现
六. blob与base64转换
// blob -> base64
/**
* 借助FileReader实现转化
* return base64Url
*/
function blobToDataURL(blob) {
let a = new FileReader();
a.onload = function (e) {
return e.target.result;
}
a.readAsDataURL(blob);
}
// base64 -> blob
/**
* 将以base64的图片url数据转换为Blob
*/
function convertBase64UrlToBlob(urlData){
const arr = urlData.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
const n = bstr.length;
const u8arr = new Uint8Array(n);
while(n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
二进制数据、blob、typedArray的相关说明
- BufferSource 是 ArrayBuffer 或 ArrayBufferView(视图,指代typedArray或者DataView) 的总称
- arrayBuffer,Uint8Array 及其他 BufferSource 是“二进制数据”,而 Blob 表示“具有类型的二进制数据”
- Blob 和低级别的二进制数据类型之间进行转换: 使用 new Blob(...) 构造函数从一个类型化数组(typed array)创建 Blob。 使用 FileReader 从 Blob 中取回 arrayBuffer(readAsArrayBuffer),然后在其上创建一个视图(view),用于二进制处理。
- 处理大型blob数据流, 转换为
stream(blob.stream()),用于分段读取;或者使用异步generator
// 从 blob 获取可读流readableStream
const readableStream = blob.stream();
// 或者通过fetch(response.body)提供可读流对象
// fetch('https://www.example.org')
// .then((response) => response.body)
// .then((rb) => {
// const reader = rb.getReader();
// };
const reader = readableStream.getReader();
while (true) {
// 对于每次迭代:value 是下一个 blob 数据片段
let { done, value } = await reader.read();
if (done) {
// 读取完毕,stream 里已经没有数据了
console.log('all blob processed.');
break;
}
// 对刚从 blob 中读取的数据片段做一些处理
console.log(value);
}
参考链接: ArrayBuffer与类型化数组、 流对象Stream