核心原理:利用
a标签download属性。但只限于同源URL,非同源的话会打开图片
so,首先,需要图片代理,以vue项目为例
//vue.config.js
module.exports = {
...
devServer: {
proxy: {
'/api/': {
target: 'https://a.**.com.cn',
ws: true,
changeOrigin: true,
pathRewrite: {
'^/api/': ''
}
},
'/api1/': {
target: 'https://img.**.com.cn',
ws: true,
changeOrigin: true,
pathRewrite: {
'^/api1/': ''
}
},
'/api2/': {
target: 'https://pic1.**.com.cn',
ws: true,
changeOrigin: true,
pathRewrite: {
'^/api2/': ''
}
}
}
}
}
其次,将图片转化为Blob,过程:img->base64->Blob
const translateImgToBase64 = (url) => {
return new Promise((resolve) => {
let canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const img = new Image();
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0);
const URLData = canvas.toDataURL('image/png');
resolve(URLData);
canvas = null;
};
img.onerror = function () {
resolve();
};
img.src = url;
});
}
const translateBase64ImgToBlob = (base64, contentType) => {
const arr = base64.split(','); // 去掉base64格式图片的头部
const bstr = atob(arr[1]); // atob()方法将数据解码
let leng = bstr.length;
const u8arr = new Uint8Array(leng);
while (leng--) {
u8arr[leng] = bstr.charCodeAt(leng); // 返回指定位置的字符的 Unicode 编码
}
const blob = new Blob([u8arr], { type: contentType });
return URL.createObjectURL(blob); // 创建URL
}
当然,其中涉及到串联, data为数据源
let newList = []
let iToBPromise = Promise.resolve();
data.forEach((item, i) => {
const tip = `转换进度:${(((i + 1) / data.length) * 100).toFixed(2)}%`;
iToBPromise = iToBPromise.then(() => this.iToBEvent(item, tip));
});
iToBPromise = iToBPromise.then(() => {
//此处进行图片下载操作,即下载newList中数据
});
const iToBEvent = (item, tip) => {
return new Promise((resolve) => {
setTimeout(async () => {
const res = await this.translateImgToBase64(item);
if (res) {
newList.push( this.translateBase64ImgToBlob(res, 'image/jpeg'));
} else {
newList.push('');
}
console.log(tip);
resolve();
}, 200);
});
}
最后,进行下载操作
<a :href="item" :download="index + 1" v-for="(item, index) in newList" :key="index">{{ item }}</a>
// script
const as = document.querySelectorAll('a');
let downImgPromise = Promise.resolve();
as.forEach((item) => {
downImgPromise = downImgPromise.then(() => this.downImgEvent(item));
});
const downImgEvent = (item)=> {
return new Promise((resolve) => {
setTimeout(() => {
item.click();
resolve();
}, 1000);
});
}