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>
相关推荐
@解忧杂货铺22 分钟前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js
F-2H2 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
gqkmiss2 小时前
Chrome 浏览器插件获取网页 iframe 中的 window 对象
前端·chrome·iframe·postmessage·chrome 插件
m0_748247555 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255025 小时前
前端常用算法集合
前端·算法
真的很上进5 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203985 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2346 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1236 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
洗发水很好用7 小时前
uniApp打包H5发布到服务器(docker)
uni-app