背景
之前系统的功能只是单独展示二维码和下载单个二维码图片。解析出二维码的内容是由前端决定的,再使用qrcode生成二维码在网页展示。最近业务需要批量下载二维码图片,考虑到由于二维码的图片大小比较小和批量下载的条数不会太多,因此可以在前端实现批量下载二维码图片功能的方案。
解决方法
一开始我直接取到用户勾选到的全部数据,然后利用for循环来通过a标签下载一张二维码图片,结果发现浏览器只能下载10张,超过10张后面的就不会下载了。这个是浏览器的保护机制,我只能把这些数据分批处理,分批的时候可以用到promise。同时封装了useBatch通用函数工具。
具体简化代码示例
示例代码可以放在html文件的srcipt标签中运行
// 假设这是你需要批量下载的内容
const list = Array.from({ length: 20 }, (v, i) => ({
fileName: `${i}`, // 文件名
txt: `${i}`, // 二维码内容
}));
// 这里是对list里每一项内容自定义处理的函数
async function handleExport(item, index) {
// 调用下载函数,传入文件名和二维码内容
download(item.fileName, item.txt);
}
// a标签下载函数
function download(fileName = '二维码图片文件名', txt = '文字内容') {
const newWidth = 300; // 二维码宽度
const newHeight = 300; // 二维码高度
const newCanvas = document.createElement('canvas'); // 创建一个新的canvas元素
newCanvas.width = newWidth;
newCanvas.height = newHeight;
const ctx = newCanvas.getContext('2d'); // 获取2D绘图上下文
// 设置背景为白色
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, newWidth, newHeight);
// 设置字体样式
ctx.font = '18px Arial';
ctx.fillStyle = '#45a8e2'; // 设置文字颜色
ctx.textAlign = 'center'; // 设置文字居中
ctx.fillText(txt, newWidth / 2, newHeight / 2); // 绘制文字
// 将canvas内容转换为Data URL
const url = newCanvas.toDataURL();
const a = document.createElement('a'); // 创建一个a标签
a.download = `${fileName}.png`; // 设置下载文件名
a.href = url; // 设置a标签的href属性
document.body.appendChild(a); // 将a标签添加到body中
a.click(); // 触发点击事件以开始下载
document.body.removeChild(a); // 下载完成后移除a标签
}
// 批量下载
function startBatchDown() {
useBatch({
list, // 需要批量处理的数据列表
fn: handleExport, // 处理每一项数据的函数
count: 5, // 每批处理的数量
});
}
// 通用的 批量下载工具函数
async function useBatch({ list = [], fn = () => {}, count = 5, time = 1000 }) {
const batches = [];
// 将列表分批
for (let i = 0; i < list.length; i += count) {
batches.push(list.slice(i, i + count));
}
// 处理每一批数据
for (const batch of batches) {
// 将每项数据映射为一个Promise
const batchPromises = batch.map((item, index) => fn(item, index));
// 并行处理当前批次的所有Promise
await Promise.all(batchPromises);
// 控制每批处理的时间间隔
await new Promise((resolve) => setTimeout(resolve, time));
}
}
// 调用批量下载函数
startBatchDown();