在uni-app中使用Painter生成小程序海报

在uni-app中使用Painter生成小程序海报

  1. 安装Painter
    从GitHub下载Painter组件:https://github.com/Kujiale-Mobile/Painter
    将painter文件夹复制到uni-app项目的components目录下

  2. 配置页面
    在需要使用海报的页面的pages.json中配置

{
  "path": "pages/share/index",
  "style": {
    "navigationBarTitleText": "分享海报",
    "usingComponents": {
      "painter": "/components/painter/painter"
    }
  }
}
  1. 在页面中使用Painter
<template>
	<!-- 海报详情 -->
	<view class="wrap">
		<!-- 引入 Painter 组件,隐藏绘制层 -->
		<painter :palette="posterData" @imgOK="onImgOK" @imgErr="onImgErr"
			style="position: absolute; left: -9999rpx;" />
		<!-- 显示生成的海报 -->
		<image v-if="imagePath" :src="imagePath" show-menu-by-longpress
			mode="aspectFill" style="width: 90%; height: 1200rpx;margin-left: 5%;" />
    </view>
</template>

<script>
	import {
		getPosterConfigDetail,
		saveAgentPoster
	} from '@/api/home.js'

	export default {
		data() {
			return {
				userName: "", // 动态用户名称
				phoneNumber: "", // 动态电话号码
				qrcodeBase64: "", // 从接口获取的 Base64 小程序码
				posterData: {}, // Painter 配置数据
				imagePath: "", // 生成的海报路径
				posterImageUrl: "", //海报背景图
				oldUserName: "",//上次绘制海报时的用户名
				oldPhoneNumber: "",
				posterName: '',
				mainImageId: '',
				posterCode: '',
				templateId: ''
			}
		},
		onLoad(option) {
	
			// id为海报模板
			this.id = option.id
			this.init()
		},
		methods: {
			init() {
				// 后台使用初始信息生成微信小程序码
				const posterConfigDetail = await getPosterConfigDetail({
					id: this.id
				})
				this.userName = res.data.userName
				this.phoneNumber = res.data.mobile
				this.posterCode = res.data.posterCode
				this.templateId = res.data.id
				this.posterImageUrl = res.data.posterImageUrl
				this.posterName = res.data.posterName
				this.qrcodeBase64 = res.data.wxCodeContent
				this.oldUserName = this.userName
				this.oldPhoneNumber = this.phoneNumber
				this.generatePoster()
			},

			// 生成海报配置
			async generatePoster() {
				const posterConfig = {
					width: "750rpx",
					height: "1334rpx",
					background: "#ffffff",
					views: [
						// 背景图
						{
							type: 'image',
							url: `${this.posterImageUrl}`,
							css: {
								width: '750rpx',
								height: '1334rpx'
							}
						},
						{
							type: "text",
							text: `联系人:${this.userName}`, // 直接注入数据
							css: {
								fontSize: "32rpx",
								bottom: "250rpx",
								left: "250rpx"
							}
						},
						{
							type: "text",
							text: `手机号:${this.phoneNumber}`,
							css: {
								fontSize: "28rpx",
								bottom: "200rpx",
								left: "250rpx"
							}
						},
						{
							type: "image",
							url: `data:image/png;base64,${this.qrcodeBase64}`,
							css: {
								width: "200rpx",
								height: "200rpx",
								bottom: "350rpx",
								left: "275rpx"
							}
						}
					]
				};
				this.posterData = posterConfig;
				console.log(this.posterData, ' this.posterData')
				// 手动触发绘制
				this.$forceUpdate()
			},

			// 生成海报成功
			onImgOK(e) {
				this.imagePath = e.detail.path;
			}
</script>            
  1. 预览、保存图片到相册
<template>
	<!-- 海报详情 -->
	<view class="wrap">
		<!-- 引入 Painter 组件,隐藏绘制层 -->
		<painter :palette="posterData" @imgOK="onImgOK" @imgErr="onImgErr"
			style="position: absolute; left: -9999rpx;" />
		<!-- 显示生成的海报 -->
		<h1 style="text-align: center;font-size: 40rpx;margin: 20rpx 0;color:#3ccc97;">{{posterName}}</h1>
		<image v-if="imagePath" :src="imagePath" show-menu-by-longpress
			mode="aspectFill" style="width: 90%; height: 1200rpx;margin-left: 5%;" />
		<view class="uni-form">
			<view class="uni-form-item uni-column">
				<view class="title">联系人: </view>
				<input class="uni-input" placeholder="请输入联系人" v-model="userName"></input>
			</view>
			<view class="uni-form-item uni-column">
				<view class="title">手机号码: </view>
				<input class="uni-input" type="number" maxlength="11" v-model="phoneNumber"
					placeholder="请输入手机号码"></input>
			</view>
			<view class="uni-form-item uni-column">
				<view class="title">海报标题: </view>
				<input class="uni-input" v-model="posterName" placeholder="请输入海报标题"></input>
			</view>
		</view>
		<!-- 触发生成的按钮 -->
		<view class="" style="padding-bottom: 60rpx;overflow: hidden;width: 100%">
			<button class="btnStyle" @click="previewImg">预览</button>
			<button class="btnStyle" @click="generateShare">生成并分享</button>
			<button class="btnStyle" @click="saveToAlbum">保存到相册</button>
		</view>
	</view>
</template>

<script>
	import {
		getPosterConfigDetail,
		saveAgentPoster
	} from '@/api/home.js'

	export default {
		data() {
			return {
				userName: "", // 动态用户名称
				phoneNumber: "", // 动态电话号码
				qrcodeBase64: "", // 从接口获取的 Base64 小程序码
				posterData: {}, // Painter 配置数据
				imagePath: "", // 生成的海报路径
				posterImageUrl: "", //海报背景图
				oldUserName: "",//上次绘制海报时的用户名
				oldPhoneNumber: "",
				posterName: '',
				mainImageId: '',
				posterCode: '',
				templateId: ''
			}
		},
		onLoad(option) {
			this.token = uni.getStorageSync('token')
			// id为海报模板
			this.id = option.id
			this.init()
		},
		created() {

		},
		methods: {
			init() {
				// 后台使用初始信息生成微信小程序码
				const posterConfigDetail = await getPosterConfigDetail({
					id: this.id
				})
				this.userName = res.data.userName
				this.phoneNumber = res.data.mobile
				this.posterCode = res.data.posterCode
				this.templateId = res.data.id
				this.posterImageUrl = res.data.posterImageUrl
				this.posterName = res.data.posterName
				this.qrcodeBase64 = res.data.wxCodeContent
				this.oldUserName = this.userName
				this.oldPhoneNumber = this.phoneNumber
				this.generatePoster()
			},
			asnyc previewImg() {
				const needStatus = await this.needRegenerate()
				if (needStatus) {
					await this.generatePoster()
					// 延迟0.5秒,等待页面重绘
					await this.delay(500)
				}
				wx.previewImage({
				  current: this.imagePath,
				  urls: [this.imagePath]
				})
			},
			// 修改用户信息后,重新生成小程序码及海报编码(生成并分享和保存到相册会上传数据到后台,可能会存储多条数据,以海报编码做区分)
			async needRegenerate() {
				// 修改用户信息后,重新生成小程序码
				if (this.userName != this.oldUserName || this.phoneNumber != this.oldPhoneNumber) {
					let that = this
					await new Promise((resolve, reject) => {
						getPosterConfigDetail({
							id: this.id
						}).then(res => {
							if (res.code == 0) {
								that.posterCode = res.data.posterCode
								that.qrcodeBase64 = res.data.wxCodeContent
								that.oldUserName = that.userName
								that.oldPhoneNumber = that.phoneNumber
							}
							resolve()
						}).catch(e => {
							reject(e)
						})
					});
					return true
				}
				return false
			}
			// 生成海报配置
			async generatePoster() {
				const posterConfig = {
					width: "750rpx",
					height: "1334rpx",
					background: "#ffffff",
					views: [
						// 背景图
						{
							type: 'image',
							url: `${this.posterImageUrl}`,
							css: {
								width: '750rpx',
								height: '1334rpx'
							}
						},
						{
							type: "text",
							text: `联系人:${this.userName}`, // 直接注入数据
							css: {
								fontSize: "32rpx",
								bottom: "250rpx",
								left: "250rpx"
							}
						},
						{
							type: "text",
							text: `手机号:${this.phoneNumber}`,
							css: {
								fontSize: "28rpx",
								bottom: "200rpx",
								left: "250rpx"
							}
						},
						{
							type: "image",
							url: `data:image/png;base64,${this.qrcodeBase64}`,
							css: {
								width: "200rpx",
								height: "200rpx",
								bottom: "350rpx",
								left: "275rpx"
							}
						}
					]
				};
				this.posterData = posterConfig;
				console.log(this.posterData, ' this.posterData')
				// 手动触发绘制
				this.$forceUpdate()
			},

			// 生成海报成功
			onImgOK(e) {
				this.imagePath = e.detail.path;
			},
			async delay(ms) {
				return new Promise(resolve => setTimeout(resolve, ms));
			},
			// 生成并分享
			async generateShare() {
				const needStatus = await this.needRegenerate()
				if (needStatus) {
					await this.generatePoster()
					// 延迟0.5秒,等待页面重绘
					await this.delay(500)
				}
				// 保存海报数据
				this.save()
				const that = this
				wx.showShareImageMenu({
					path: that.imagePath, //图片地址必须为本地路径或者临时路径
					success: (re) => {
						console.log(re, "分享成功")
					},
					fail: (re) => {
						console.log(re, "分享失败")
					}
				
				});
			},
			// 保存到相册
			saveToAlbum() {
				const needStatus = await this.needReGenerate()
				if (needStatus) {
					await this.generatePoster()
					// 延迟0.5秒,等待页面重绘
					await this.delay(500)
				}
				// 保存海报数据
				this.save()
				const that = this
				uni.saveImageToPhotosAlbum({
					filePath: that.imagePath,
					success: () => {
						uni.showToast({
							title: '保存成功',
							icon: 'success'
						});
					},
					fail: (err) => {
						console.error('保存失败:', err);
						if (err.errMsg.includes('auth')) {
							that.showAuthSetting('需要相册权限才能保存图片');
						} else {
							uni.showToast({
								title: '保存失败',
								icon: 'none'
							});
						}
					}
				});
			},

			// 显示权限设置引导
			showAuthSetting(content) {
				uni.showModal({
					title: '权限申请',
					content: content || '需要您授权权限才能继续操作',
					confirmText: '去设置',
					success: (res) => {
						if (res.confirm) {
							uni.openSetting();
						}
					}
				});
			},
			// 保存到后台
			sync save() {
				saveAgentPoster({
					mainImageId: this.mainImageId,
					posterCode: this.posterCode,
					posterName: this.posterName,
					templateId: this.templateId,
				}).then(res => {
					if (res.code == 0) {
						console.log("请求成功")
					}
				})
			},
			onImgErr(e) {
				console.log(e, '生成海报出错了')
			}
		}
	}
</script>

<style scoped lang="scss">
	.wrap {
		width: 100vw;
		height: 100%;
		background-color: #f7f7f7;

		// position: relative;
	}

	.uni-form {
		background-color: #f7f7f7;
		width: 96%;
		margin-left: 2%;

		.uni-form-item {
			margin-top: 20rpx;
			background-color: #fff;

			.uni-input {
				color: #333;
				font-size: 30rpx;
				height: 81rpx;
				padding-left: 10rpx;
				// border: none;

				border-radius: 10rpx;
			}

			.title {
				font-size: 30rpx;
				color: #333;
				// font-weight: 600;
				line-height: 81rpx;
				margin-bottom: 20rpx;
				float: left;
				width: 150rpx;
				text-align: right;
				padding-left: 5rpx;
			}

			.u-button--square {
				color: #3ccc97 !important;
			}

			.u-input__content__field-wrapper__field {
				text-align: left !important;
			}

		}
	}

	.btnStyle {
		width: 28%;
		float: left;
		border-radius: 20rpx;
		height: 80rpx;
		line-height: 80rpx;
		margin-left: 4%;

	}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GalenZhang888

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值