uniApp 分享海报
uniapp生成海报,带适配,文字多出省略号,圆角矩形
<template>
<view>
<view class="invite_img" @click="showposter">生成海报</view>
<canvas canvas-id="poster" id="poster" class="poster-box"></canvas>
<u-popup v-model="show" mode="center">
<image :src="posterImg" class="posterImg" mode=""></image>
<image src="../../static/images/poster_close.png" mode="" class="close" @click="close"></image>
<view class="button" @click="saveposter">保存到相册</view>
</u-popup>
</view>
</template>
<script>
export default {
data() {
return {
_w:0,
userInfo: {
//海报所需数据
avatar_url: 'https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF',
qRCodeImgUrl: 'https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF',
nickname: '笑一个吧123123哈哈哈哈哈哈哈哈哈',
mobile: '182****1022',
code: '123456'
},
bgImgUrl: 'https://img2.baidu.com/it/u=2556294903,542088888&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=281', //海报背景
finger: 'https://img1.baidu.com/it/u=3298452815,4076337725&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=501', //海报手指图片
show: false,
posterImg: '',
loading: false
};
},
async onReady() {
this.getSystemInfo(); //获取屏幕宽度适配比例
},
async onLoad() {
this.showposter();
},
onShow() {
},
mounted() {
},
methods: {
//将canvas转图片
async showposter() {
// if (this.detail.is_vip != 1) {
// uni.showModal({
// title: '您还不是会员',
// content: '需要购买会员勋章后邀请,用户才能获得分销金',
// cancelText: '前往购买',
// confirmText: '知道了',
// cancelColor: '#8392A6',
// success: (res) => {
// if (res.confirm) {
// console.log('用户点击确定');
// } else if (res.cancel) {
// uni.navigateTo({
// url: "/pages/vipDetail/vipDetail?id=" + this.detail.member_deal_list[0].id
// })
// }
// }
// })
// return
// }
uni.showLoading({
title: '海报生成中...'
});
// 绘制海报所需数据 如果是本地图片使用this.getImageInfoUrl
let bgImgUrl = await this.createImgUrl(this.bgImgUrl);
let fingerUrl = await this.createImgUrl(this.finger);
let avatar_url = await this.createImgUrl(this.userInfo.avatar);
let qRCodeImgUrl = await this.createImgUrl(this.userInfo.qr_code);
console.log('posterMsg', this.userInfo.avatar, this.userInfo.qr_code);
this.posterCanvas({
bgImgUrl,
fingerUrl,
headImgUrl: avatar_url,
CodeImgUrl: qRCodeImgUrl,
nickName: this.userInfo.nickname,
phone: this.userInfo.mobile,
code: this.userInfo.code
});
},
//保存图片
saveposter() {
const that = this;
uni.getImageInfo({
src: this.posterImg,
success: res => {
console.log('res', res.path);
uni.saveImageToPhotosAlbum({
filePath: res.path,
success: function() {
uni.showToast({
title: '保存成功'
});
},
fail: function(err) {
console.log('err1', err);
}
});
},
fail: err => {
console.log('errr', err);
}
});
},
close() {
this.show = false;
},
// 绘制海报
posterCanvas({
bgImgUrl = '', headImgUrl = '', nickName = '', phone = '', CodeImgUrl = '', code = '', fingerUrl = '' }) {
let that = this;
let ctx = uni.createCanvasContext('poster', this);
//填充白色背景
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, this.calculate(310), this.calculate(494.5));
//头部背景图
ctx.drawImage(bgImgUrl, 0, 0, this.calculate(310), this.calculate(200));
ctx.restore();
//头像
console.log('头像');
ctx.save()
//ctx.drawImage(headImgUrl, this.calculate(16), this.calculate(182), this.calculate(68), this.calculate(68));
this.circleImgTwo(ctx, headImgUrl, this.calculate(16), this.calculate(182), this.calculate(68), this.calculate(68), 10);
ctx.restore();
// 名字
console.log('名字');
this.dealWords({
ctx,
fontSize: 18,
color: '#292F3E',
word: nickName,
maxWidth: this.calculate(210),
x: this.calculate(93),
y: this.calculate(210),
maxLine: 1
});
ctx.restore();
// 电话号码
console.log('电话');
ctx.setFillStyle('#6E717A');
ctx.setFontSize(12);
ctx.fillText(phone, this.calculate(93), this.calculate(246));
ctx.restore();
//绘制二维码
console.log('二维码');
ctx.drawImage(CodeImgUrl, this.calculate(75), this.calculate(265), this.calculate(160), this.calculate(160));
ctx.restore();
//绘制邀请码
ctx.setFillStyle('#292F3E');
ctx.setFontSize(12);
ctx.fillText('专属邀请码:', this.calculate(88), this.calculate(445));
ctx.restore();
//邀请码
ctx.setFillStyle('#FF0677');
ctx.setFontSize(17);
ctx.fillText(code, this.calculate(162), this.calculate(445));
ctx.restore();
// 提示语
ctx.drawImage(fingerUrl, this.calculate(39), this.calculate(465), this.calculate(20), this.calculate(14));
ctx.restore();
ctx.setFillStyle('#5C6476');
ctx.setFontSize(12);
ctx.fillText('分享给你的好友,让TA跟你一起做任务', this.calculate(65), this.calculate(476));
ctx.restore();
ctx.draw();
// 海报绘制完成
// 转换成图片
setTimeout(() => {
uni.canvasToTempFilePath({
x: 0,
y: 0,
width: that.calculate(310),
height: that.calculate(494.5),
// destWidth: this.calculate(930),
// destHeight: this.calculate(1483.5),
quality: 1,
canvasId: 'poster',
success: res => {
console.log(res.tempFilePath, '生成图片');
that.posterImg = res.tempFilePath;
uni.hideLoading();
that.show = true;
},
fail: err => {
console.log('err', err);
uni.showToast({
title: '生成失败',
icon: 'none'
});
uni.hideLoading();
}
});
}, 1000);
},
// 获取系统适配
getSystemInfo() {
let _this = this;
uni.getSystemInfo({
success(res) {
_this._w = res.windowWidth;
}
});
},
// 画布计算比例
calculate(num) {
let w = this._w;
let n = parseInt((w * num) / 375);
return n;
},
// 创建本地地址
createImgUrl: url =>
new Promise((resolve, reject) => {
uni.downloadFile({
url,
success: val => resolve(val.tempFilePath),
fail: err => {
console.log('e', err);
uni.showToast({
title: '图片出现错误',
icon: 'none'
});
reject(err);
}
});
}),
// 本地资源路径
getImageInfoUrl: url =>
new Promise((resolve, reject) => {
uni.getImageInfo({
src: url,
success: val => resolve(val.path),
fail: err => {
console.log('e', err);
reject(err);
}
});
}),
/* 绘制圆角矩形 需要在前面save一下 再用restore恢复
* 参数说明
* ctx Canvas实例
* img 图片地址
* x x轴坐标
* y y轴坐标
* w 宽度
* h 高度
* r 弧度大小
*/
circleImgTwo(ctx, img, x, y, w, h, r) {
// 画一个图形
if (w < 2 * r) r = w / 2;
if (h < 2 * r) r = h / 2;
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
ctx.strokeStyle = '#FFFFFF'; // 设置绘制圆形边框的颜色
ctx.stroke();
ctx.clip(); //从原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内(不能访问画布上的其他区域)。可以在使用 clip() 方法前通过使用 save() 方法对当前画布区域进行保存,并在以后的任意时间对其进行恢复(通过 restore() 方法) 需要在前面save一下
ctx.drawImage(img, x, y, w, h);
},
//处理文字多出省略号显示
dealWords(options) {
options.ctx.setFontSize(options.fontSize); //设置字体大小
options.ctx.setFillStyle(options.color); //设置字体颜色
var allRow = Math.ceil(options.ctx.measureText(options.word).width / options.maxWidth); //实际总共能分多少行
var count = allRow >= options.maxLine ? options.maxLine : allRow; //实际能分多少行与设置的最大显示行数比,谁小就用谁做循环次数
var endPos = 0; //当前字符串的截断点
for (var j = 0; j < count; j++) {
var nowStr = options.word.slice(endPos); //当前剩余的字符串
var rowWid = 0; //每一行当前宽度
if (options.ctx.measureText(nowStr).width > options.maxWidth) {
//如果当前的字符串宽度大于最大宽度,然后开始截取
for (var m = 0; m < nowStr.length; m++) {
rowWid += options.ctx.measureText(nowStr[m]).width; //当前字符串总宽度
if (rowWid > options.maxWidth) {
if (j === options.maxLine - 1) {
//如果是最后一行
options.ctx.fillText(nowStr.slice(0, m - 1) + '...', options.x, options.y + (j + 1) * 18); //(j+1)*18这是每一行的高度
} else {
options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * 18);
}
endPos += m; //下次截断点
break;
}
}
} else {
//如果当前的字符串宽度小于最大宽度就直接输出
options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * 18);
}
}
}
}
};
</script>
<style lang="scss" scoped>
.header {
background: url(../../static/images/memberCenter_bg.png) no-repeat;
height: 520rpx;
background-size: cover;
background-position: center;
padding-bottom: 30rpx;
position: relative;
::v-deep .u-navbar {
background: rgba(0, 0, 0, 0) !important;
}
}
.on ::v-deep .u-navbar {
background: RGBA(196, 213, 255, 1) !important;
}
::v-deep .u-mode-center-box {
background: none;
}
.userInfo {
display: flex;
align-items: center;
padding-left: 40rpx;
margin-top: 15rpx;
.headerImg {
height: 120rpx;
width: 120rpx;
border-radius: 50%;
margin-right: 26rpx;
}
.username {
font-size: 40rpx;
font-family: PingFang SC;
font-weight: bold;
color: #292f3e;
.vip {
height: 36rpx;
width: 36rpx;
margin-left: 16rpx;
}
}
.inviteed {
margin-top: 10rpx;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(92, 100, 118, 0.6);
.inviteed_num {
font-size: 32rpx;
font-family: PingFang SC;
font-weight: bold;
color: rgba(92, 100, 118, 0.8);
}
}
}
.explain {
// position: absolute;
box-sizing: border-box;
margin: 0 24rpx;
margin-top: 48rpx;
// top: 310rpx;
// left: 24rpx;
// right: 24rpx;
// width: 702rpx;
// height: 403rpx;
background: #ffffff;
padding: 29rpx 33rpx 33rpx 33rpx;
box-shadow: 0px 0px 25rpx 0px rgba(83, 105, 161, 0.1);
border-radius: 16rpx;
.explain_title {
font-size: 30rpx;
font-family: PingFang SC;
font-weight: bold;
color: #292f3e;
margin-bottom: 10rpx;
// margin-top: 29rpx;
}
}
.invite_img {
height: 175rpx;
margin: 0 24rpx;
margin-top: 15rpx;
.invite_img_cover {
height: 175rpx;
width: 100%;
}
}
.buy_vip_title {
font-size: 32rpx;
font-family: PingFang SC;
font-weight: bold;
color: #292f3e;
margin: 51rpx 0 0rpx 32rpx;
}
.buy_vip_item {
// width: 686rpx;
height: 196rpx;
background: #fcfbf7;
border: 2rpx solid #eaac3c;
border-radius: 16rpx;
margin: 0 32rpx;
margin-top: 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 42rpx;
}
.vip_name {
font-size: 36rpx;
font-family: PingFang SC;
font-weight: bold;
color: #cc9512;
}
.vip_time {
font-size: 26rpx;
font-family: PingFang SC;
font-weight: 500;
color: #cc9512;
margin-top: 20rpx;
}
.vip_money_num {
font-size: 32rpx;
font-family: PingFang SC;
font-weight: bold;
color: #292f3e;
}
.buy_button {
margin-top: 24rpx;
width: 160rpx;
height: 56rpx;
background: linear-gradient(90deg, #f2e098 0%, #f1c370 100%);
border-radius: 28rpx;
font-size: 24rpx;
text-align: center;
line-height: 56rpx;
font-family: PingFang SC;
font-weight: bold;
color: #934b0c;
}
.buy_vip_name {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}
.buy_vip_money {
display: flex;
justify-content: space-between;
flex-direction: column;
align-items: center;
}
.poster-box {
width: 620rpx;
height: 989rpx;
position: fixed;
// left: 10rpx;
left: 110vw;
top: 0rpx;
z-index: -1;
// background-color: #fff;
// border: 1px solid red;
// z-index: -1;
}
.posterImg {
width: 620rpx;
height: 989rpx;
border-radius: 20rpx;
}
.button {
width: 400rpx;
height: 88rpx;
line-height: 88rpx;
margin: 0 auto;
text-align: center;
font-size: 30rpx;
font-family: PingFang SC;
font-weight: 500;
color: #262a32;
background: #ffffff;
border-radius: 16rpx;
margin-top: 48rpx;
}
.close {
height: 32rpx;
width: 32rpx;
position: absolute;
top: 20rpx;
right: 20rpx;
}
</style>