Uniapp微信小程序:自定义海报生成方案。支持保存到本地,二维码生成,富文本解析(个人学习记录)

📅 发布时间:2026/7/15 13:10:52 👁️ 浏览次数:
Uniapp微信小程序:自定义海报生成方案。支持保存到本地,二维码生成,富文本解析(个人学习记录)
示例代码template view classpage :style{ paddingTop: 180 rpx } !-- 页面主体内容 -- view classpage-content !-- 标题区域 -- view classtitle邀请好友加入龙集/view view classsub-title邀请好友扫码有惊喜/view !-- 海报生成容器l-painter -- l-painter csswidth:680rpx; height: 800rpx; position: absolute;top:0rpx; zIndex: 1;background: #FFFFFF; failhandlePainterFail donehandlePainterDone pathTypeurl refposterRef performance !-- 海报背景图 -- !-- l-painter-image src../static/icons/qrcode_bg.png csswidth: 680rpx; height: 800rpx;position: absolute; top: 50%; left: 50%;transform: translate(-50%,-50%); zIndex: 1 / -- !-- Logo -- !-- l-painter-image src../static/icons/会员卡.png csswidth: 82px; height: 82rpx; position: absolute; top: 44rpx; left: 50%; transform: translateX(-50%); zIndex: 1 / -- !-- 主标题 -- l-painter-text text龙集 cssfont-size: 44rpx; line-height: 64rpx; font-weight: 600; color: #333; position: absolute; top: 138rpx; left: 50%; transform: translateX(-50%);zIndex: 1 / !-- 副标题 -- l-painter-text text邀请好友扫码有惊喜 cssfont-size: 28rpx; line-height: 40rpx; color: #999; position: absolute; top: 214rpx; left: 50%; transform: translateX(-50%); / !-- 二维码 -- l-painter-qrcode cssposition: absolute;top:350rpx;zIndex: 9;width: 260rpx; height: 260rpx;margin:0 auto; :textqrcodeContent :options{ useDynamicSize: true, areaColor: transparent, backgroundColor: transparent, foregroundColor: #400303, margin: 30 } / /l-painter !-- 操作按钮区域 -- view classqr-option view classitem view classsaveIamge clickhandleSavePoster保存图片/view /view /view /view /view /template script setup import { ref } from vue; // 二维码内容 const qrcodeContent ref(code:58086544); // 海报相关状态 const posterRef ref(null); // 海报组件引用 const isPosterRendered ref(false); // 海报是否绘制完成 const isSavingPoster ref(false); // 是否正在保存海报 const tempPosterPath ref(); // 海报临时文件路径 /** * 海报绘制失败回调 */ const handlePainterFail () { console.error([海报绘制] 失败); isPosterRendered.value false; uni.showToast({ title: 海报生成失败, icon: none }); }; /** * 海报绘制完成回调 */ const handlePainterDone () { console.log([海报绘制] 完成); isPosterRendered.value true; // 标记绘制完成 }; /** * 保存海报到相册 */ const handleSavePoster async () { // 校验1海报未绘制完成 if (!isPosterRendered.value) { uni.showToast({ title: 海报正在生成请稍后, icon: none, duration: 1500 }); return; } // 校验2正在保存中防止重复点击 if (isSavingPoster.value) return; try { isSavingPoster.value true; uni.showLoading({ title: 保存中..., mask: true }); // 生成海报临时文件路径 const posterRes await posterRef.value.canvasToTempFilePath({ fileType: jpg, quality: 1, pathType: url }); // 校验临时路径是否生成成功 if (posterRes posterRes.tempFilePath) { tempPosterPath.value posterRes.tempFilePath; await saveImageToAlbum(); // 保存到相册 } else { uni.showToast({ title: 获取海报临时路径失败, icon: none }); } } catch (error) { console.error([海报保存] 生成临时路径失败, error); uni.showToast({ title: 海报保存失败, icon: none, duration: 2000 }); } finally { isSavingPoster.value false; // 解锁保存状态 uni.hideLoading(); // 隐藏加载提示 } }; /** * 保存图片到相册权限处理 */ const saveImageToAlbum () { return new Promise((resolve, reject) { // #ifndef H5 // 1. 获取用户授权设置 uni.getSetting({ success: (settingRes) { // 已授权相册权限 if (settingRes.authSetting[scope.writePhotosAlbum]) { doSaveToAlbum(resolve, reject); } // 未授权发起授权请求 else { uni.authorize({ scope: scope.writePhotosAlbum, success: () doSaveToAlbum(resolve, reject), fail: () handleAuthFail(resolve, reject) }); } }, fail: () { uni.showToast({ title: 获取授权状态失败, icon: none, duration: 2000 }); reject(获取授权状态失败); } }); // #endif }); }; /** * 处理相册授权失败逻辑 */ const handleAuthFail (resolve, reject) { uni.showModal({ title: 授权提示, content: 需要授权相册权限才能保存图片请前往设置开启, confirmText: 去设置, cancelText: 取消, success: (modalRes) { if (modalRes.confirm) { // 打开设置页面 uni.openSetting({ success: (openRes) { if (openRes.authSetting[scope.writePhotosAlbum]) { doSaveToAlbum(resolve, reject); } else { uni.showToast({ title: 未开启授权保存失败, icon: none }); reject(用户未开启相册授权); } }, fail: () { uni.showToast({ title: 打开设置失败, icon: none }); reject(打开设置页面失败); } }); } else { reject(用户取消授权); } }, fail: () reject(模态框调用失败) }); }; /** * 实际执行保存到相册操作 */ const doSaveToAlbum (resolve, reject) { uni.saveImageToPhotosAlbum({ filePath: tempPosterPath.value, success: () { resolve(); uni.showToast({ title: 已保存到相册, icon: success, duration: 2000 }); }, fail: (error) { console.error([相册保存] 失败, error); reject(error); uni.showToast({ title: 保存相册失败, icon: none, duration: 2000 }); } }); }; /script style langscss scoped .page { min-height: 100vh; background-color: #F8F8FA; box-sizing: border-box; position: relative; } .page-content { text-align: center; padding: 35rpx; .title { font-weight: 600; font-size: 48rpx; color: #3D3D3D; line-height: 70rpx; margin-top: 54rpx; } .sub-title { font-weight: 400; font-size: 24rpx; color: #333333; line-height: 34rpx; margin-top: 12rpx; margin-bottom: 30rpx; } .qr-option { margin-top: 60rpx; display: flex; padding: 0 40rpx; justify-content: space-around; .item { display: flex; flex-direction: column; align-items: center; gap: 6rpx; .saveIamge { font-size: 36rpx; line-height: 52rpx; color: #3D3D3D; width: 322rpx; height: 118rpx; background: #FFFFFF; display: flex; justify-content: center; align-items: center; border-radius: 100rpx; } } } } /style依赖插件https://ext.dcloud.net.cn/plugin?id2389