最近接到一个需求,需要在列表上显示二维码图片,用户还可以勾选多个二维码图片,打包为 zip 文件下载
将 URL 转为二维码图片并不复杂,qrcodejs、node-qrcode 都是很成熟的方案
打包 zip 听起来很恐怖,但用上 jszip 就很简单了
这篇文章介绍的是 node-qrcode + jszip 的解决方案。前端框架用的是 React,不过核心逻辑是通用的
一、生成二维码
首先安装 node-qrcode
yarn add qrcode @types/qrcode
在浏览器环境下,node-qrcode 提供了这几个 API:toCanvas()、toDataURL()、toString()
推荐使用 toDataURL, 然后直接将路径作为 src 用于 <img /> 标签
还可以出传入一些配置项 Option 来设置二维码图片的颜色、格式等
import QRCode from 'qrcode'; const opts: QRCode.QRCodeToDataURLOptions = { errorCorrectionLevel: 'H', type: 'image/jpeg', margin: 1, color: { dark:"#010599FF", light:"#FFBF60FF" } } QRCode.toDataURL('text', opts).then(url => { const img = document.getElementById('image') img.src = url })
基于以上 API,可以封装一个简单的二维码组件:
import React, { useEffect, useState } from 'react'; import QRCode from 'qrcode'; import type { QRCodeToDataURLOptions } from 'qrcode'; export type QrcodeImgProps = { url: string; options?: QRCodeToDataURLOptions; }; /** 二维码图片组件 */ export const QrcodeImg: React.FC<QrcodeImgProps> = ({ url, options }) => { const [src, setSrc] = useState<string>(''); useEffect(() => { QRCode.toDataURL(url, options) .then((x) => { setSrc(x); }) .catch(() => { setSrc(''); console.error('生成二维码失败'); }); }, [url, options]); return src ? <img className="qrcode" src={src} /> : null; }; export default QrcodeImg;
二、批量导出 ZIP
安装 jszip
yarn add jszip
基本用法如下:
const zip = new JSZip(); // 直接压缩文件 zip.file("Hello.txt", "Hello World\n"); // 创建文件夹 const img = zip.folder("images"); // 创建图片并放进文件夹 img.file("smile.gif", imgData, {base64: true}); // 生成 zip 文件 zip.generateAsync({type:"blob"}).then(function(content) { // content 为 'application/zip' 文件流,需要手动下载 });
jszip 可以基于 base64 创建图片文件,而上面通过 qrcode 生成的是一个 dataUrl,所以需要转换一下:
/** 从 dataUrl 截取 Base64 字符串*/ function dataUrlToBase64(dataUrl: string) { if (typeof dataUrl !== 'string') return ''; const idx = dataUrl.indexOf('base64,') + 'base64,'.length; return dataUrl.substring(idx); }
最后一个批量导出二维码的函数就出来了:
import QRCode from "qrcode"; import JSZip from "jszip"; export type QrcodeItem = { /** 二维码标题 */ name: string; /** 二维码地址 */ url: string; }; /** * 批量下载二维码 * @param data 二维码数据集 * @param name 打包后的文件名 */ export function downloadBatchQrcodeImg(data: QrcodeItem[], name?: string) { if (!Array.isArray(data) || !data.length) { return console.error('二维码数据异常'); } const zipName = name || '未命名'; const zip = new JSZip(); const folder = zip.folder(zipName); // 批量创建二维码 Promise.all(data.map((item) => QRCode.toDataURL(item.url))).then((values) => { values.forEach((v, index) => { const content = dataUrlToBase64(v); // qrcode 默认生成 png 图片 folder?.file(`${data[index].name}.png`, content, { base64: true }); }); zip.generateAsync({ type: 'blob' }).then(function (content) { // 下载文件 downloadBlobFile(content, `${zipName}.zip`, 'application/zip'); }); }); }
最后贴一下 downloadBlobFile 函数,是一个比较粗糙的下载文件方法,仅供参考
export type MsNavigator = { msSaveOrOpenBlob?: (blob: any, defaultName?: string) => boolean; }; /** 下载文件流, 默认导出 Excel */ export default function downloadBlobFile( data: Blob, fileName: string, type = 'application/vnd.ms-excel', ) { const Navigator = window.navigator as MsNavigator; if (Navigator?.msSaveOrOpenBlob) { Navigator.msSaveOrOpenBlob(data, fileName); } else { const aTag = document.createElement('a'); // 获取 blob 本地文件连接 (blob 为纯二进制对象,不能够直接保存到磁盘上) const downUrl = window.URL.createObjectURL(new Blob([data], { type })); // 定义导出文件的命名 aTag.href = downUrl; aTag.download = fileName; aTag.click(); window.URL.revokeObjectURL(downUrl); } }
标签:const,zip,批量,data,二维码,qrcode,type From: https://www.cnblogs.com/wisewrong/p/17106385.html