微信小程序 太阳码生成分享海报 (此处为公用组件,在需求页面引入即可。其中使用到uview)
在这里插入代码片<template>
<view class="content">
<!-- <view class="box"><u-button type="primary" @click="share_qrcode()">生成海报</u-button></view> -->
<u-mask :show="share_qrcode_flag" @click="share_qrcode_flag = false" :zoom="false" :custom-style="{ background: 'rgba(0,0,0,.8)' }" :duration="0">
<view class="sq_box">
<view class="tz_box qrcode_box">
<!-- <view class="close_box" @click="handleClose"><u-icon name="close" color="#ffffff"></u-icon></view> --> // 关闭按钮(目前是点击遮罩层后关闭页面)
<view class="share_qrcode">
<canvas canvas-id="myCanvas" style="width: 690px;height:1040px; position: fixed;top: -10000px;"></canvas>
<image @longpress="this.showSaveImgWin = true" style="width: 100%; height: 100%;border-radius: 14rpx;" :src="canvasToTempFilePath"></image>
</view>
</view>
</view>
</u-mask>
<u-modal
v-model="showSaveImgWin"
content="确定要保存图片吗"
@confirm="saveShareImg(canvasToTempFilePath)"
@cancel="this.showSaveImgWin = false"
:show-cancel-button="true"
></u-modal>
</view>
</template>
<script>
export default {
data() {
return {
ratio: 1,
ctx: null, // 创建canvas对象
canvasToTempFilePath: null, // 保存最终生成的导出的图片地址
openStatus: true, // 声明一个全局变量判断是否授权保存到相册
share_qrcode_flag: false,
showSaveImgWin: false, //保存图片到相册
userInfo:"",
option: {
//绘制海报内容
codeUrl: "", //小程序太阳码
coverUrl: 'https://pic1.zhimg.com/80/v2-2714df42147132464a71af391ed04be4_720w.jpg', //题库图片
headUrl: 'https://pic1.zhimg.com/80/v2-b9df1fdfe67f2177d5c84af90dcadfc1_720w.jpg?source=1940ef5c', //头像
bgUrl: 'https://pic3.zhimg.com/v2-8fbde0f9ac6a19a23aa839e73394618a_b.jpg', //图片背景填充,和 fillStyle 只能传一个,bgUrl 优先级高于 fillStyle
fillStyle: '#0688ff', //纯色背景填充颜色
}
};
},
mounted() {
// 父组件传递给子组件事件
uni.$off("team_code").$on("team_code",value => {
this.option.codeUrl = value.url
this.userInfo = value.info
this.share_qrcode()
})
},
methods: {
share_qrcode() {
if (!this.canvasToTempFilePath) {
this.createCanvasImage(this.option);
}
this.share_qrcode_flag = true;
},
handleClose(){
this.share_qrcode_flag = false
uni.hideLoading()
},
//获取图片信息
downloadFileImg(url) {
return new Promise(resolve => {
uni.getImageInfo({
src: url,
success: res => {
resolve(res.path);
},
fail: err => {
console.log(err);
uni.showToast({
title: '网络错误请重试',
icon: 'loading'
});
}
});
});
},
// 生成海报
async createCanvasImage(option) {
// 点击生成海报数据埋点
if (!this.ctx) {
uni.showLoading({
title: '生成中...'
});
let code = this.downloadFileImg(this.option.codeUrl);
let cover = this.downloadFileImg(option.coverUrl);
let headImg = this.downloadFileImg(this.userInfo.avatarUrl);
let bgUrl = '../../static/personal/icon-team_bg.png';
Promise.all([headImg, code, cover, bgUrl]).then(result => {
const ctx = uni.createCanvasContext('myCanvas', this);
let canvasWidthPx = 750 * this.ratio,
canvasHeightPx = 1040 * this.ratio,
avatarurl_width = 140, //绘制的头像宽度
avatarurl_heigth = 140, //绘制的头像高度
avatarurl_x = 280, //绘制的头像在画布上的位置
avatarurl_y = 50, //绘制的头像在画布上的位置
codeurl_width = 300, //绘制的二维码宽度
codeurl_heigth = 300, //绘制的二维码高度
codeurl_x = 195, //绘制的二维码在画布上的位置
codeurl_y = 300, //绘制的二维码在画布上的位置
coverurl_width = 0, //绘制的封面宽度
coverurl_heigth = 0, //绘制的封面高度
coverurl_x = 0, //绘制的封面在画布上的位置
coverurl_y = 0; //绘制的封面在画布上的位置
if (option.bgUrl) {
ctx.drawImage(result[3], 0, 0, 690, 1040); // 背景图片需要本地
} else {
//绘制圆角矩形
ctx.save();
ctx.translate(0, 0);
//绘制圆角矩形的各个边
this.drawRoundRectPath(ctx, 690, 1040, 14);
ctx.fillStyle = option.fillStyle || '#0688ff'; //若是给定了值就用给定的值否则给予默认值
ctx.fill();
ctx.restore();
}
ctx.save(); // 先保存状态 已便于画完圆再用
ctx.beginPath(); //开始绘制
//先画个圆 前两个参数确定了圆心 (x,y) 坐标 第三个参数是圆的半径 四参数是绘图方向 默认是false,即顺时针
ctx.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math.PI * 2, false);
ctx.clip(); //画了圆 再剪切 原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内
ctx.drawImage(result[0], avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth); // 推进去图片
ctx.restore(); //恢复之前保存的绘图上下文状态 可以继续绘制
ctx.font = 'normal bold 28px sans-serif';
ctx.setFillStyle('#171717'); // 文字颜色
ctx.textAlign = 'center' // 文字居中显示
ctx.fillText(this.userInfo.nickName,355,230)
ctx.drawImage(result[1], codeurl_x, codeurl_y, codeurl_width, codeurl_heigth); // 绘制二维码
ctx.fillText("扫码加入", 355, 660); // 绘制文字
ctx.fillText(this.userInfo.company_name, 355, 720); // 绘制文字
ctx.fillText("长按图片,可保存到相册", 355, 780); // 绘制文字
ctx.drawImage(result[2], coverurl_x, coverurl_y, coverurl_width, coverurl_heigth); // 绘制封面
ctx.draw(false, () => {
// canvas画布转成图片并返回图片地址
uni.canvasToTempFilePath(
{
canvasId: 'myCanvas',
success: res => {
this.canvasToTempFilePath = res.tempFilePath;
this.showShareImg = true;
uni.showToast({
title: '绘制成功'
});
},
fail: err => {
uni.showToast({
title: '绘制失败'
});
},
complete: () => {
uni.hideLoading();
uni.hideToast();
}
},
this
);
});
});
}
},
drawRoundRectPath(cxt, width, height, radius) {
cxt.beginPath(0);
//从右下角顺时针绘制,弧度从0到1/2PI
cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
//矩形下边线
cxt.lineTo(radius, height);
//左下角圆弧,弧度从1/2PI到PI
cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
//矩形左边线
cxt.lineTo(0, radius);
//左上角圆弧,弧度从PI到3/2PI
cxt.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);
//上边线
cxt.lineTo(width - radius, 0);
//右上角圆弧
cxt.arc(width - radius, radius, radius, (Math.PI * 3) / 2, Math.PI * 2);
//右边线
cxt.lineTo(width, height - radius);
cxt.closePath();
},
// 保存到系统相册
saveShareImg(canvasToTempFilePath) {
uni.saveImageToPhotosAlbum({
filePath: canvasToTempFilePath,
success: () => {
this.$u.toast('保存成功,快去分享到朋友圈吧~');
},
fail: () => {
this.$u.toast('保存失败~');
}
});
}
}
};
</script>
<style lang="scss">
.sq_box {
display: flex;
height: 100%;
justify-content: center;
align-items: center;
color: #333333;
padding:0 60rpx ;
.tz_box {
border-radius: 14rpx;
padding: 40rpx;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
width: 100%;
text-align: center;
line-height: 50rpx;
height: 970rpx;
.close_box {
position: absolute;
left: 50%;
bottom: -100rpx;
border: 4rpx solid #ffffff;
width: 60rpx;
height: 60rpx;
margin-left: -30rpx;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.share_qrcode {
width: 100%;
height: 100%;
}
.tz_title {
font-size: 34rpx;
font-weight: 600;
}
.content_box {
margin: 50rpx 0;
text-align: left;
.inf {
font-weight: bold;
font-size: 36rpx;
.copy {
font-weight: 0;
color: rgb(85, 104, 147);
font-size: 30rpx;
}
}
}
}
.qrcode_box {
padding: 0;
}
}
</style>
不喜勿喷,简单记录