前言
产品姐:“怎么有的图片预览可以保存成功,有的却提示保存失败?”
我:“不能够呀,正常图片应该没问题的哇”
产品姐摇摇头:“那这个二维码你给我保存下。”
我长按——“图像保存失败”。
产品姐一脸坏笑:“Bug 转给你咯。”
我:“……那个,后端哥哥 ~ 你的base64二维码图片可以转一下嘛(卑微)”
后端哥:“转毛,转不了一点”
我:
无可奈何~~~~~花落去 似曾相识燕归来
来~~~~~~~来,键来-----------
问题场景复现
言归歪传,在我们的 UniApp + Vue3 + TypeScript 项目中,二维码是通过 Base64 形式传输的,例如:
form.qrCode = 'data:image/png;base64,iVBORw0K...';
原本我们使用 wd-img
组件,通过如下方式展示二维码:
<wd-img :width="'150rpx'" :height="'150rpx'" :src="form.qrCode" mode="aspectFit" :enable-preview="true"/>
✅ 普通图片:在 App 上预览时,长按可保存;
❌ Base64 图片:提示“保存失败”。
改造目标
- ✅ 支持点击 Base64 图片进入预览
- ✅ 支持长按弹出菜单(如“保存图片”)
- ✅ 选择保存后,手动将 Base64 转为本地文件并保存到相册
步骤 1:点击触发自定义预览
将原本的 :enable-preview="true"
移除,改为绑定 @click
手动处理。
<wd-img
:width="'150rpx'"
:height="'150rpx'"
:src="form.qrCode"
mode="aspectFit"
@click.stop="imgPreview(form.qrCode)"
/>
💡 说明:
- 使用
@click.stop
阻止事件冒泡,防止误触。 - 进入预览逻辑交由我们自己改造控制。
步骤 2:封装预览函数 imgPreview
使用 uni.previewImage
进行预览,同时通过 longPressActions
修改长按图片显示操作菜单,如不填默认为保存相册。
使用 itemList
自定义长按后的操作菜单,可修改为你想要的['发送给朋友', '保存图片', '收藏']等等之类的
export const imgPreview = (url: string) => {
uni.previewImage({
urls: [url],
longPressActions: {
itemList: ['保存图片'],
success: function (data) {
// 用户点击了“保存图片”
if (data.tapIndex === 0) {
saveBase64Img(url)
}
},
fail: function (err) {
console.log('预览长按失败:', err);
}
}
});
};
💡 说明:
tapIndex === 0
表示用户点击了“保存图片”。- Base64 图片并不能直接保存,需转换处理。
步骤 3:封装 Base64 保存函数 saveBase64Img
关键是利用 plus.nativeObj.Bitmap
创建位图对象,从 Base64 中生成真实图片文件。
export const saveBase64Img = (base64: string) => {
const bitmap = new plus.nativeObj.Bitmap('base64img');
bitmap.loadBase64Data(
base64,
() => {
const fileName = `_doc/${Date.now()}.png`;
bitmap.save(
fileName,
{ overwrite: true },
() => {
const realPath = plus.io.convertLocalFileSystemURL(fileName);
uni.saveImageToPhotosAlbum({
filePath: realPath,
success: () => {
uni.showToast({ title: '保存成功', icon: 'none' });
bitmap.clear();
},
fail: () => {
uni.showToast({ title: '保存失败', icon: 'none' });
bitmap.clear();
}
});
},
(err) => {
console.error('图片保存失败:', err);
bitmap.clear();
}
);
},
(err) => {
console.error('base64 解析失败:', err);
bitmap.clear();
}
);
};
🔍 代码解析:
bitmap.loadBase64Data(base64)
:将 Base64 转换为位图。_doc/
:保存至 App 的私有沙盒路径中,避免权限问题。plus.io.convertLocalFileSystemURL()
:转换为可用于保存相册的真实路径。bitmap.clear()
:释放内存,别忘了清理资源!
小结:
- 🚫 Base64 图片在 App 中无法直接预览后长按保存。
- ✅ 自定义预览 + 保存逻辑能完美绕过这个限制。
- 🔑 关键三板斧:
plus.nativeObj.Bitmap
+_doc/
路径 +convertLocalFileSystemURL()
。
PS:我用的UI组件库是Wot,另外img和image也同理适用
彩蛋时间 🎁
产品姐:“这么快改好了?顺便把图片长按转发/收藏/点赞也做了吧,应该都很快吧”
我:“很快,离职手续办得很快”
感谢阅读!
下次再见!🌈