效果  
 
 封装组件,父组件 ref 调用 downImgUrl()函数,其他根据自己需求改  
< 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> 
	< /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: { 
			// 下载
			downCli ( )  { 
				if(  this.imgUrl &&   this.imgUrl !=  '' ) { { 
						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" > 
.flexaround{ 
	display: flex; justify-content: space-around; 
} 
.flexalign{ 
	display: flex; align-items: center; 
} 
.font26{ 
	font-size: 26rpx; 
	font-family: PingFang-SC-Medium; 
} 
	.canvas-wrap { 
		margin: 20 % 45rpx; 
		width: calc( 100 % - 90rpx) ; 
		height: 940rpx; 
		// background-color: 
	} 
	.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: 
			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: 
				border-radius: 50 %; 
				image { 
					width: 88rpx; 
					height: 88rpx; 
				} 
			} 
		} 
	} 
< /style>