二维码生成工具使用@uqrcode/js,版本4.0.7
官网地址:uQRCode 中文文档(不建议看可能会被误导)
本项目采用了npm引入方式,也可通过插件市场引入,使用上会略有不同
准备工作:
安装:pnpm add @uqrcode/js
引入:import UQRCode from '@uqrcode/js/uqrcode'
二维码生成及转图片逻辑:
javascript
<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并转为在线url
const fileRes: any = await base64ToTempFile({ image: canvas.toDataURL() })
// 转为临时url
uni.downloadFile({
url: fileRes.data.fileUrl,
success: (res) => {
pageData.qrCodePath = res.tempFilePath
}
});
});
};
页面绘制:
javascript
<!-- 隐藏的 Canvas(用于绘制截图) -->
<canvas
canvas-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.screenWidth
screenHeight.value = systemInfo.screenHeight
// 2. 设置canvas尺寸(考虑设备像素比)
const dpr = systemInfo.pixelRatio || 1
const 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 * rpxToPx
const fontSizeDesc = 32 * rpxToPx
const centerX = canvasWidth / 2
// 标题
canvasContext.setFontSize(fontSizeTitle)
canvasContext.setFillStyle('#000000') // 改为黑色确保可见
canvasContext.setTextAlign('center')
const displayText = pageData.name?.length > 7
? pageData.name.substring(0, 6) + '...'
: pageData.name
canvasContext.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, // 考虑DPI
height: 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
})
}
}