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>
相关推荐
小汤猿人类2 小时前
uniapp媒体
uni-app·媒体
Random_index2 小时前
#名词区别篇:npx pnpm npm yarn区别
前端·npm
B.-3 小时前
Remix 学习 - 路由模块(Route Module)
前端·javascript·学习·react·web
不修×蝙蝠3 小时前
Javascript应用(TodoList表格)
前端·javascript·css·html
加勒比海涛4 小时前
ElementUI 布局——行与列的灵活运用
前端·javascript·elementui
你不讲 wood4 小时前
postcss 插件实现移动端适配
开发语言·前端·javascript·css·vue.js·ui·postcss
前端小程4 小时前
使用vant UI实现时间段选择
前端·javascript·vue.js·ui
whyfail5 小时前
React 事件系统解析
前端·javascript·react.js
小tenten6 小时前
js延迟for内部循环方法
开发语言·前端·javascript
幻影浪子6 小时前
Web网站常用测试工具
前端·测试工具