UniApp+Vue3微信小程序二维码生成、转图片、截图保存整页
二维码生成工具使用@uqrcode/js,版本4.0.7
官网地址:uQRCode 中文文档(不建议看可能会被误导)
本项目采用了npm引入方式,也可通过插件市场引入,使用上会略有不同
准备工作:
安装:pnpm add @uqrcode/js
引入:import UQRCode from '@uqrcode/js/uqrcode'
二维码生成及转图片逻辑:
<view class="qrcode-icon"><!-- 设置 canvas 的固定尺寸 --><canvas type="2d" id="qrcodeCanvas" canvas-id="qrcodeCanvas" style="width: 360rpx; height: 360rpx;"></canvas>
</view>// 生成二维码
const generateWXQRCode = async () => {const query = uni.createSelectorQuery();query.select('#qrcodeCanvas').fields({ node: true, size: true }, () => {}).exec(async (res) => {if (!res[0]?.node) {console.error('未找到二维码Canvas节点');return;}const canvas = res[0].node;const ctx = canvas.getContext('2d');const { width, height } = res[0];// 设置 canvas 的绘制尺寸(避免模糊)canvas.width = width;canvas.height = height;// 创建二维码实例const qrcode = new UQRCode({data: `111111`,size: Math.min(width, height),canvasContext: ctx});// 绘制二维码await qrcode.make();await qrcode.draw();// 获取base64并转为在线urlconst fileRes: any = await base64ToTempFile({ image: canvas.toDataURL() })// 转为临时urluni.downloadFile({url: fileRes.data.fileUrl,success: (res) => {pageData.qrCodePath = res.tempFilePath}});});
};
页面绘制:
<!-- 隐藏的 Canvas(用于绘制截图) --><canvascanvas-id="screenshotCanvas":style="{width: `${screenWidth}px`,height: `${screenHeight}px`,position: 'fixed',left: '-9999px'}">
</canvas>const screenWidth = ref(300)
const screenHeight = ref(400)
// 保存当前页面为图片
const takeScreenshot = async () => {try {// 1. 获取系统信息const systemInfo = await uni.getSystemInfo()screenWidth.value = systemInfo.screenWidthscreenHeight.value = systemInfo.screenHeight// 2. 设置canvas尺寸(考虑设备像素比)const dpr = systemInfo.pixelRatio || 1const canvasWidth = Math.min(screenWidth.value, 750)const canvasHeight = Math.min(screenHeight.value, 1334)const rpxToPx = screenWidth.value / 750// 3. 获取canvas上下文const canvasContext = uni.createCanvasContext('screenshotCanvas')// 4. 绘制白色背景(确保有内容)canvasContext.setFillStyle('#FFFFFF')canvasContext.fillRect(0, 0, canvasWidth, canvasHeight)// 5. 绘制背景图(使用绝对路径)const bgPath = '/subPages/static/qrcode-bg.png' // 确保图片存在于此路径try {canvasContext.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight)} catch (err) {console.error('背景图加载失败:', err)// 使用备用颜色canvasContext.setFillStyle('#F0F0F0')canvasContext.fillRect(0, 0, canvasWidth, canvasHeight)}// 6. 绘制文本内容const fontSizeTitle = 72 * rpxToPxconst fontSizeDesc = 32 * rpxToPxconst centerX = canvasWidth / 2// 标题canvasContext.setFontSize(fontSizeTitle)canvasContext.setFillStyle('#000000') // 改为黑色确保可见canvasContext.setTextAlign('center')const displayText = pageData.name?.length > 7? pageData.name.substring(0, 6) + '...': pageData.namecanvasContext.fillText(displayText, centerX, 260 * rpxToPx)// 副标题canvasContext.setFontSize(fontSizeDesc)canvasContext.fillText('邀请您加入车队', centerX, 320 * rpxToPx)// 绘制二维码const qrSize = 200;const qrX = (canvasWidth - qrSize) / 2;const qrY = 480 * rpxToPx;canvasContext.drawImage(pageData.qrCodePath, qrX, qrY, qrSize, qrSize);// 失效时间canvasContext.setFillStyle('#000000')canvasContext.fillText(`${pageData.selectedTime} 23:59:59后失效`,centerX,920 * rpxToPx)// 7. 执行绘制(关键修改)await new Promise<void>((resolve, reject) => {canvasContext.draw(true, () => {setTimeout(() => {// 检查Canvas内容console.log('Canvas绘制完成')resolve()}, 500) // 增加延迟确保渲染完成})})// 8. 生成临时文件const { tempFilePath } = await uni.canvasToTempFilePath({canvasId: 'screenshotCanvas',quality: 1, // 最高质量width: canvasWidth * dpr, // 考虑DPIheight: canvasHeight * dpr})// 9. 保存到相册await uni.saveImageToPhotosAlbum({filePath: tempFilePath})uni.showToast({title: '保存成功',icon: 'success'})} catch (err) {console.error('截图失败:', err)uni.showToast({title: '保存失败: ' + (err.errMsg || '未知错误'),icon: 'none',duration: 3000})}
}