uniapp canvas生成海报

效果

封装组件,父组件 ref 调用 downImgUrl()函数,其他根据自己需求改

bash 复制代码
//(内容,扫码打开的页面)
this.$refs.canvasImg.downImgUrl(this.detail,'/pagesA/detail/postDetail?id='+this.detailID)
bash 复制代码
<template>
	<view>
		<view class="bgpart">

			<canvas class="canvas-wrap" canvas-id="canvasID" type="2d"></canvas>

			<view class="popPart">
				<view>
					<view class="share-list">
						<view class="share-item flexaround flexalign" @click="shareToFriend(1)">
							<view class="iconImg flexalign flexaround">
								<image src="/static/sharePop/share1.png" mode=""></image>
							</view>
							<text class="font26" style="margin-top: 16rpx;">微信</text>
						</view>
						<view class="share-item flexaround flexalign" @click="shareToFriend(2)">
							<view class="iconImg flexalign flexaround">
								<image src="/static/sharePop/share2.png" mode=""></image>
							</view>
							<text class="font26" style="margin-top: 16rpx;">朋友圈</text>
						</view>
						<view class="share-item flexaround flexalign" @click="downCli">
							<view class="iconImg flexalign flexaround" style="width: 88rpx;height: 88rpx;">
								<u-icon name="download" size="30"></u-icon>
							</view>
							<text class="font26" style="margin-top: 16rpx;">下载</text>
						</view>
					</view>
				</view>
				<view class="share-header flexalign flexaround" style="background: #fff;" @click="$emit('close')">
					取消
				</view>
			</view>
		</view>
		<permission ref="permission"></permission>
	</view>
</template>

<script>
	import {
		indexsettingPoster
	} from "@/api/all.js"
	export default {
		name: "sharePoster",
		props: {},
		data() {
			return {
				logo: '/static/logo.png',
				bgimg: '',
				detail: {},
				imgUrl:'',//完成海报图
				qrCode:''
			};
		},
		created() {
			
		},
		methods: {
			shareToFriend(e){
				if(e == 1){ //微信
					uni.share({
					    provider: "weixin",
					    scene: "WXSceneSession",
					    type: 2,
					    imageUrl: this.imgUrl,
					    success: function (res) {
							console.log(res)
							
					    },fail: function (err) {
							console.log(err)
					        // this.com.msg('')
					    }
					});
				}else{ //朋友圈
					uni.share({
					    provider: "weixin",
					    scene: "WXSenceTimeline",
					    type: 2,
					    imageUrl: this.imgUrl,
					    success: function (res) {
							console.log(res)
					    },fail: function (err) {
							console.log(err)
					        // this.com.msg('失败')
					    }
					});
				}
			},
			// 下载
			downCli() {
				if( this.imgUrl &&  this.imgUrl != ''){
					this.$refs.permission.requestPermission('photoLibrary').then(async res => {
						uni.saveImageToPhotosAlbum({
							filePath: this.imgUrl,
							success: function () {
								console.log('save success'); 
								uni.showToast({
									icon:"none",
									title:'已下载'
								})
							}
						});
					})
				}
			},
			async downImgUrl(e,url,type) {
				await indexsettingPoster({url:url}).then(res => {
					this.bgimg = res.data.posterThumb
					this.qrCode = res.data.qrCode
				})
				let canW = 320;
				let canH = 450;
				let ctx = uni.createCanvasContext('canvasID', this);
				// ctx.setFillStyle("transparent"); //设置canvas背景颜色
				// ctx.fillRect(0, 0, 346, 500) //设置canvas画布大小
				ctx.drawImage(this.bgimg, 0, 0, canW, canH) //背景
				ctx.drawImage(this.logo, 18, 20, 36, 36) //logo
				// ctx.drawImage(e.dynamicQRcode, 255, 370, 70, 70) //二维码
				ctx.drawImage(this.qrCode, 230, 370, 70, 70) //二维码
				//绘制圆形头像
				this.drawCircular(ctx, e.headPortrait, 26, 398, 40, 40) 
				// 名字
				ctx.setFontSize(14)
				ctx.setFillStyle("#ffffff")
				ctx.fillText(e.nickName, 74, 424)
				
				// 绘制标题,多余文字自动换行
				ctx.setFontSize(26)
				ctx.setFillStyle("#2C3E68")
				ctx.textAlign = "center"
				let str = type ? e.teamName : e.dynamicTitle
				
				// 字符串总长度
				let _strLength = str.length > 24 ? 24 : str.length
				// 总结截取次数
				let _strNum = Math.ceil(_strLength / 8)
				// 每次开始截取字符串的索引
				let _strHeight = 0
				// 绘制的字体 x,y的初始位置
				let _strX = 345 / 2,
					_strY = 90
				let strIndex = 223
				// 开始截取
				for (let i = 0; i < _strNum; i++) {
					strIndex = _strY + i * 40
					ctx.fillText(str.substr(_strHeight + i * 9, 9), _strX, _strY + i * 34)
				}
				// 绘制内容
				ctx.setFontSize(13)
				ctx.setFillStyle("#4FB0FF")
				let cont = type ? e.teamContent : e.dynamicDescribe
				// 字符串总长度
				let _contLength = cont.length  > 120 ? 120 : cont.length
				// 总结截取次数
				let _contNum = Math.ceil(_contLength / 20)
				// 每次开始截取字符串的索引
				let _contHeight = 0
				// 绘制的字体 x,y的初始位置
				let _contX = 345 / 2,
					_contY = 180
				let contIndex = 223
				// 开始截取
				for (let i = 0; i < _contNum; i++) {
					contIndex = _contY + i * 20
					ctx.fillText(cont.substr(_contHeight + i * 20, 20), _contX, _contY + i * 22)
				}
				//详情图
				let img = type ? e.teamPics : e.dynamicPics //团队,动态
				img.split(',').forEach((el,index)=>{
					if(index == 0){
						ctx.drawImage( el , 50, 290, 70, 70) //二维码
					}else if(index == 1){
						ctx.drawImage( el , 130, 290, 70, 70) //二维码
					}else if(index == 2){
						ctx.drawImage( el , 210, 290, 70, 70) //二维码
					}
				})
				
				ctx.draw(false, () => {
					// 返回canvas图片信息
					uni.canvasToTempFilePath({
						canvasId: 'canvasID',
						success: (res) => {
							this.imgUrl = res.tempFilePath
						},
						fail: function(err) {
							console.log(err)
						}
					})
				})
			},
			// 绘制圆形头像
			drawCircular(ctx, url, x, y, width, height) {
				//画圆形头像
				var avatarurl_width = width;
				var avatarurl_heigth = height;
				var avatarurl_x = x;
				var avatarurl_y = y;
				ctx.save(); //先保存状态,已便于画完园再用
				ctx.beginPath(); //开始绘制
				ctx.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math
					.PI * 2, false);
				ctx.setFillStyle("#FFFFFF")
				ctx.fill() //保证图片无bug填充
				ctx.clip(); //剪切
				ctx.drawImage(url, avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth); //推进去图片
				ctx.restore();
			},
		
		}
	}
</script>

<style scoped lang="scss">
	.canvas-wrap {
		margin: 20% 45rpx;
		width: calc(100% - 90rpx);
		height: 940rpx;
		// background-color: #fff;
	}

	.bgpart {
		width: 100vw;
		height: 100vh;
		background-color: rgba(0, 0, 0, 0.5);
		position: fixed;
		left: 0;
		top: 0;
		z-index: 99;

		.popPart {
			width: 100%;
			height: 360rpx;
			background-color: #f5f5f5;
			border-radius: 20rpx 20rpx 0 0;
			position: fixed;
			left: 0;
			bottom: 0;
			z-index: 99;
		}
	}

	.share-header {
		line-height: 80rpx;
	}

	.share-list {
		margin: 20rpx 0 60rpx 0;
		display: flex;
		/* flex-direction: row; */
		flex-wrap: wrap;

		.share-item {
			margin-top: 30rpx;
			min-width: 20%;
			flex-direction: column;

			.iconImg {
				background-color: #fff;
				border-radius: 50%;

				image {
					width: 88rpx;
					height: 88rpx;
				}
			}
		}
	}
</style>
相关推荐
我要洋人死25 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人36 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人37 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR42 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香44 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#