定义: Blob对象表示不可变的,包含原始数据的类文件对象。
- 两个参数
- 数据类型的数据对象(ArrayBuffer,ArraybufferView,Blob,String等)
- MINE类型
- 结果:产生一个Blob对象
一、文件下载
1.1、a标签 href下载
浏览器不识别响应头,或者不能解析的格式,会当成文件直接下载。
1.2、base64
将文件转成base64后,作为a,img标签的src,css的url()
1.3、Blob流
注释: 1.ArrayBuffer接收读取文件的二进制流格式数据
2.window.URL.createObjectURL(blob);将Blob流转换成DOMString
个人使用: ==使用a标签的download下载(FF不支持download属性)==
window.open,个别浏览器能识别个别图片图片格式,是预览,而非下载
// 请求文件数据
axios({
method: 'GET',
url: record.url,
responseType: 'blob'
}).then(res=>{
if(!res){
this.$message.warning('文件下载失败');
return
}
// 创建Blob对应格式的Blob对象
let blob = new Blob([res.data], {type: mimeType});
// 检测是否兼容download属性(FF不支持download属性)
if('download' in document.createElement("a")){
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = record.name;
link.click();
link.remove();
window.URL.revokeObjectURL(link.href);
}else{
// 缺点:个别浏览器能识别个别图片格式,会直接浏览,而非下载
let targetUrl = window.URL.createObjectURL(blob);
window.open(targetUrl);
window.URL.revokeObjectURL(targetUrl);
}
}).catch(err=>{
console.error(err)
})
问题:兼容搜狗浏览器,但是360浏览器上window.open打开的是标签页,也不是窗口
解决方案:使用iframe(测试:无法修改文件名称)
function IEdownloadFile(fileName, contentOrPath){
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = contentOrPath;
document.body.appendChild(ifr);
// 保存页面 -> 保存文件
ifr.contentWindow.document.execCommand('SaveAs', false, fileName);
document.body.removeChild(ifr);
}
// base64 编码文件
var isImg = contentOrPath.slice(0, 10) === "data:image";
// dataURL 的情况
isImg && ifr.contentWindow.document.write("<img src='" +
contentOrPath + "' />");
二、压缩
- 文件流转Base64
- 图片有损压缩,toDataURL
/*
* 文件流转Base64
* @param {file} file 图片对象
* @param {number} quality 图片质量 范围: [0,1] 超出默认为0.92
* */
fileToBase64ByQuality(file,quality){
return new Promise((resolve, reject) => {
if(file.type === 'image/jpeg' || file.type === 'image/webp'){
let fileReader = new FileReader()
let type = file.type
if (window.URL || window.webkitURL) {
resolve(this.fileCompress(URL.createObjectURL(file), quality, type, file.name))
} else {
fileReader.onload = () => {
resolve(this.fileCompress(fileReader.result, quality, type, file.name))
}
fileReader.onerror = (e) => {
reject(e)
}
fileReader.readAsDataURL(file)
}
}else{
resolve(file);
}
})
},
- 文件压缩
/*
* 规则:只能是在格式为image/jpeg,和image/webp得情况下才能用
* @param {file} fileBase64 图片base64数据
* */
fileCompress(fileBase64, quality, mimeType, fileName){
// 图片最大宽度
const MAX_WIDTH = 800
let cvs = document.createElement('canvas');
let img = document.createElement('img');
img.crossOrigin = 'anonymous'
return new Promise((resolve, reject) => {
img.src = fileBase64
// 图片偏移值
let offetX = 0
img.onload = () => {
if (img.width > MAX_WIDTH) {
cvs.width = MAX_WIDTH
cvs.height = img.height * MAX_WIDTH / img.width
offetX = (img.width - MAX_WIDTH) / 2
} else {
cvs.width = img.width
cvs.height = img.height
}
let ctx = cvs.getContext("2d").drawImage(img, 0, 0, cvs.width, cvs.height)
let imageData = cvs.toDataURL(mimeType, quality)
resolve(this.convertBase64UrlToBlob(imageData, mimeType, fileName))
}
})
},
- base64转文件流
/**
* base64转文件流
* @param {base64} base64数据
* @param {string} mimeType MIME类型
* @return {file} 文件blob二进制数据
*/
convertBase64UrlToBlob(base64, mimeType, fileName){
let bytes = window.atob(base64.split(',')[1])
let ab = new ArrayBuffer(bytes.length)
let ia = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
//base64转成Blob
let _blob = new Blob([ab], { type: mimeType })
let files = new File([_blob], fileName, {type: mimeType})
return files
},
大文件分片上传
Blob对象有个slice方法,可将大文件按相同大小切割成n-1个,加上最后一节
function fileSlice(file, piece = 1024 * 1024){
let allSize = file.size;
let start = 0;
let end = start + piece;
let filePieceArr = [];
while(end > allSize){
filePieceArr.push(file.slice(start, end));
start = end;
end = start + piece;
}
return filePieceArr
}
刚开始写文章,可以的话,麻烦给点建议,谢谢