uniapp + uview-plus 微信小程序二维码生成和保存完整解决方案
📋 项目背景
在开发微信小程序时,经常需要实现二维码的生成和保存功能。本文档提供了一个基于 uniapp + uview-plus 框架的完整解决方案,彻底解决了以下常见问题:
- ✅ Canvas API 兼容性问题
- ✅ 微信小程序权限处理
- ✅ u-qrcode 组件保存方法不可用
- ✅ 组件内部方法依赖问题
- ✅ 时序问题和异步处理
🎯 核心设计思路
采用纯API方案,完全绕过Canvas操作:
- 使用 u-qrcode 组件显示二维码
- 保存时通过第三方API重新生成相同内容的二维码
- 下载生成的图片并保存到相册
🔧 技术栈
- 框架: uniapp
- UI库: uview-plus v3.4.54
- 目标平台: 微信小程序
- Vue版本: Vue 3 + Composition API
💻 完整代码实现
1. QrcodeGenerator.vue 组件
<template>
<view class="qrcode-generator">
<view class="qrcode-container">
<u-qrcode
ref="qrcodeRef"
:val="qrcodeText"
:size="qrcodeSize"
:background="backgroundColor"
:foreground="foregroundColor"
:loadMake="loadMake"
@click="onQrcodeClick"
@result="onQrcodeResult"
></u-qrcode>
</view>
</view>
</template>
<script setup>
import {
ref, computed, watch, onMounted, nextTick } from 'vue'
// 定义 props
const props = defineProps({
// 二维码内容(必传)
text: {
type: String,
required: true,
default: ''
},
// 二维码尺寸
size: {
type: Number,
default: 200
},
// 二维码边距
margin: {
type: Number,
default: 0
},
// 背景颜色
backgroundColor: {
type: String,
default: '#ffffff'
},
// 前景颜色
foregroundColor: {
type: String,
default: '#000000'
},
// 容错级别 L/M/Q/H
correctLevel: {
type: String,
default: 'M'
},
// 是否立即生成
loadMake: {
type: Boolean,
default: true
}
})
// 定义 emits
const emit = defineEmits(['click', 'save', 'generated'])
// 响应式数据
const qrcodeRef = ref(null)
const qrcodeResult = ref('') // 保存二维码生成结果
const qrcodeTempFilePath = ref('') // 保存二维码临时文件路径
// 计算属性
const qrcodeText = computed(() => props.text || 'https://example.com')
const qrcodeSize = computed(() => props.size)
// 监听文本变化,重新生成二维码
watch(() => props.text, (newText, oldText) => {
console.log('QrcodeGenerator文本变化:', {
oldText, newText })
if (newText && newText !== oldText && qrcodeRef.value) {
console.log('触发u-qrcode重新生成二维码')
// 使用nextTick确保DOM更新后再生成
nextTick(() => {
if (qrcodeRef.value && qrcodeRef.value._makeCode) {
qrcodeRef.value._makeCode()
}
})
}
}, {
immediate: true })
// 二维码点击事件
const onQrcodeClick = () => {
emit('click', {
text: qrcodeText.value,
size: qrcodeSize.value
})
}
// 二维码生成完成回调
const onQrcodeResult = (result) => {
console.log('二维码生成完成:', result)
qrcodeResult.value = result
// 保存临时文件路径,这是u-qrcode组件生成的可用于保存的路径
qrcodeTempFilePath.value = result
emit('generated', result)
}
// 保存二维码方法 - 完全不用Canvas的方案
const downloadQrcode = async () => {
console.log('=== 纯API方式保存二维码 ===')
try {
// 第一步:获取当前二维码内容
const qrText = qrcodeText.value
if (!qrText || qrText === 'https://example.com') {
throw new Error('二维码内容无效')
}
console.log('二维码内容:', qrText)
// 第二步:检查相册权限
await checkAlbumPermission()
// 第三步:使用第三方API生成二维码图片
const tempFilePath = await generateQrcodeByAPI(qrText)
// 第四步:保存到相册
await saveToAlbum(tempFilePath)
// 第五步:显示成功提示
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
})
} catch (error) {
console.error('保存失败:', error)
uni.showToast({
title: error.message || '保存失败',
icon: 'none',
duration: 3000
})
}
}
// 检查相册权限
const checkAlbumPermission = () => {
return new Promise((resolve, reject) => {
// #ifdef MP-WEIXIN
uni.getSetting({
success: (