前言
在 UniApp 开发中,使用 uv-ui 的 uv-qrcode 组件生成二维码非常方便。但是,当我们试图将这个生成的二维码保存到手机相册时,往往会遇到各种"坑",比如:
-
调用
toTempFilePath拿到的不是路径而是 Base64 字符串? -
saveImageToPhotosAlbum报错文件不支持? -
用户拒绝了相册权限后怎么引导重新开启?
本文将为你提供一套**"保姆级"**的完整解决方案,涵盖从获取数据、Base64转文件到权限处理的全流程。
1. 核心流程概览
保存二维码的过程本质上就是把"内存里的画"变成"相册里的图"。主要分为三个关键步骤:
-
获取数据:调用组件方法,把当前的二维码画面导出来。
-
数据清洗(关键避坑点):判断导出的是"文件路径"还是"Base64 字符串"。如果是 Base64,系统保存接口不支持,必须手动转成二进制文件。
-
保存入库:调用系统 API 存入相册,并优雅地处理权限授权问题。
2. 详细实现步骤
第一步:获取组件实例并导出
首先,在 template 中给组件绑定 ref,并在 JS 中调用组件内部的 toTempFilePath 方法。
Template 代码:
HTML
javascript
<template>
<view>
<uv-qrcode ref="qrcode" value="https://www.example.com" size="200px"></uv-qrcode>
<button @click="saveQrcode">保存二维码</button>
</view>
</template>
JS 代码:
JavaScript
javascript
methods: {
saveQrcode() {
const ref = this.$refs.qrcode;
// 必须判空,防止组件没加载完就调用报错
if (!ref) return;
ref.toTempFilePath({
success: (res) => {
// 拿到结果:res.tempFilePath
// 这里千万别急着存,先交给下一步清洗函数处理
this.handleSave(res.tempFilePath);
},
fail: (err) => {
console.error('获取图片失败', err);
}
});
}
}
第二步:数据清洗与转换(核心黑科技)
这是最容易翻车的地方!res.tempFilePath 返回的数据有两种情况:
-
情况 A(理想) :
wxfile://tmp/xxxx.png------ 真实路径,直接存。 -
情况 B(现实) :
data:image/png;base64,iVBORw...------ Base64 字符串,系统 API 无法直接保存。
我们需要使用 uni.getFileSystemManager 将 Base64 写入为本地临时文件。
JavaScript
javascript
handleSave(filePath) {
// 1. 判断是否是 Base64 数据流
if (filePath.startsWith('data:image')) {
// === 核心黑科技开始 ===
// 创建文件管理器
const fs = uni.getFileSystemManager();
// 去掉头部 'data:image/png;base64,',只保留纯数据
const code = filePath.split(',')[1];
// 把 Base64 字符串转成二进制 Buffer
const buffer = uni.base64ToArrayBuffer(code);
// 定义一个本地临时文件名(使用时间戳防止重名)
const fileName = `${uni.env.USER_DATA_PATH}/qrcode_${Date.now()}.png`;
// 写入本地文件
fs.writeFile({
filePath: fileName,
data: buffer,
encoding: 'binary',
success: () => {
// 写入成功!现在 fileName 就是一个真实的本地路径了
console.log('转换成功,临时路径:', fileName);
this.saveImageToAlbum(fileName);
},
fail: (err) => {
console.log('Base64转文件失败', err);
uni.showToast({ title: '图片转换失败', icon: 'none' });
}
});
// === 核心黑科技结束 ===
} else {
// 2. 如果本身就是路径(如微信小程序环境部分情况),直接保存
this.saveImageToAlbum(filePath);
}
}
第三步:保存到相册与权限处理
最后一步调用 saveImageToPhotosAlbum,同时要考虑到用户可能第一次手抖点了"拒绝授权",我们需要引导用户去设置页重新开启。
JavaScript
javascript
saveImageToAlbum(filePath) {
uni.showLoading({ title: '保存中...' });
uni.saveImageToPhotosAlbum({
filePath: filePath,
success: () => {
uni.hideLoading();
uni.showToast({ title: '保存成功', icon: 'success' });
},
fail: (err) => {
uni.hideLoading();
console.log('保存失败', err);
// 检查是不是因为权限问题失败的
// 不同端报错信息可能不同,覆盖 auth deny 和 authorize:fail
if (err.errMsg && (err.errMsg.includes('auth deny') || err.errMsg.includes('authorize:fail'))) {
// 引导用户去设置页开启权限
uni.showModal({
title: '权限提示',
content: '保存图片需要您授权访问相册,请前往设置开启权限',
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: (settingRes) => {
if (settingRes.authSetting['scope.writePhotosAlbum']) {
uni.showToast({ title: '授权成功,请重试', icon: 'none' });
}
}
});
}
}
});
} else {
// 其他错误(如文件路径错误等)
uni.showToast({ title: '保存失败,请重试', icon: 'none' });
}
}
});
}
3. 避坑总结与 H5 兼容
核心避坑点
-
先打印 :遇到组件(Charts/Painter/QRCode)导出失败,先
console.log看看路径是不是data:image开头。 -
转文件 :只要是 Base64,必须用
getFileSystemManager转存成临时文件,不要试图直接传给保存接口。
H5 端的特殊处理
上述代码主要适用于 小程序 和 App 端。 如果是 H5 端 ,uni.saveImageToPhotosAlbum 是无效的(浏览器机制限制)。H5 端需要通过创建 <a> 标签模拟点击下载:
JavaScript
javascript
// H5 专用保存逻辑
if (
// #ifdef H5
true
// #endif
) {
const a = document.createElement('a');
a.href = filePath; // 这里的 filePath 可以直接是 Base64
a.download = 'qrcode.png';
a.click();
return;
}
结语:这套逻辑是处理 UniApp 图片保存的标准"满分"答案。如果你觉得有用,欢迎点赞收藏,下次遇到类似需求直接 Copy 代码!