效果展示:
项目要求:点击分享绘制海报,并实现分享到好友,朋友圈,并保存
先实现绘制海报
<view class="data_item" v-for="(item,index) in dataList" :key="index"
@click="goDetail(item,index)">
<view class="data_bot">
<view class="share" @click.stop="goShare(item,index)">
<image :src="getimg('share_gray.png')" style="width: 36rpx;height: 36rpx;"></image>
<view class="share_tt">分享</view>
</view>
</view>
</view>
<view class="post_box" :class="isShare?' ':'post_box2'">
<view class="post">
<canvas style="width: 327px; height:482px;margin: 0 auto;" canvas-id="firstCanvas1"></canvas>
</view>
</view>
// 生成海报
goShare(item, index) {
let _this = this;
this.shareId = item.id
this.isShare = true
// uni.hideTabBar()
let userInfo = uni.getStorageSync('userInfo')
uni.getImageInfo({
src: userInfo.avatar,
success: function(res) {
if (res.path) {
_this.canvasr(item, index, res.path, userInfo.nickname);
}
},
});
},
// 画海报
canvasr(item, index, avatar, username) {
let ctx = uni.createCanvasContext('firstCanvas1');
// 背景图
let postImage = '../../static/images/poster_bg.png'; //背景图
ctx.globalAlpha = 0; // 设置图像透明度为0 为了让背景透明
ctx.setFillStyle('#ffffff'); // 默认白色
ctx.fillRect(0, 0, 327, 482);
ctx.globalAlpha = 1; // 设置图像透明度为1
ctx.drawImage(postImage, 0, 0, 327, 482); // (图片,x,y,宽,高)背景图
ctx.save();
// 头像
ctx.restore();
// let avatar = userInfo.avatar + "?timestamp=" + Date.now(); //地址栏加入新参数 解决canvas图片跨域问题
this.drawAvatar(ctx, avatar, 30, 20, 15)
// 昵称 +
ctx.setFontSize(12); //设置字体字号
ctx.setFillStyle('#000000'); //设置字体颜色
// ctx.fillText(username, 65, 39); // (文字,x,y)
let _strlineW = 0;
let nickname = '';
let actI = 0;
for (let i = 0; i < username.length; i++) {
_strlineW += ctx.measureText(username[i]).width;
if(_strlineW <= 60){
ctx.fillText(username, 65, 39); // (文字,x,y)
}else if (_strlineW > 60 && _strlineW <= 70) {
actI = i
nickname = username.substring(0, i) + '…'
ctx.fillText(nickname, 65, 39); // (文字,x,y)
}else{
nickname = username.substring(0, actI-1) + '…'
ctx.fillText(nickname, 65, 39); // (文字,x,y)
}
}
// 分享了一个点子
let txt = '我发现了一个不错的点子';
ctx.setFontSize(12); //设置字体字号
ctx.setFillStyle('#999999'); //设置字体颜色
ctx.fillText(txt, 135, 39); // (文字,x,y)
// 内容开始引号图
let startImage = '../../static/images/poster_quote_up.png'; //背景图
ctx.drawImage(startImage, 30, 70, 32, 32); // (图片,x,y,宽,高)背景图
ctx.save();
ctx.restore();
// 内容
let content = item.idea_name;
this.drawtext(ctx, content, 30, 130, 32, 267)
// 内容结束引号图
let endImage = '../../static/images/poster_quote_down.png'; //背景图
ctx.drawImage(endImage, 265, 310, 32, 32); // (图片,x,y,宽,高)背景图
ctx.save();
ctx.restore();
// 一条直线
ctx.setFillStyle('#D8D8D8'); // 默认白色
ctx.fillRect(30, 362, 267, 0.5); //x y 宽 高
ctx.restore();
// logo图
let logoImage = '../../static/images/aiyop_logo.png'
this.drawAvatar(ctx, logoImage, 30, 402, 15)
ctx.save();
ctx.restore();
// AI有谱
let title = 'AI有谱';
ctx.setFontSize(13); //设置字体字号
ctx.setFillStyle('#000000'); //设置字体颜色
ctx.fillText(title, 70, 415); // (文字,x,y)
// 心中有谱,奇思妙想也靠谱
let intro = '心中有谱,奇思妙想也靠谱';
ctx.setFontSize(10); //设置字体字号
ctx.setFillStyle('#666666'); //设置字体颜色
ctx.fillText(intro, 70, 430); // (文字,x,y)
// 二维码
let qrImage = '../../static/images/logo_program.jpg';
this.drawAvatar(ctx, qrImage, 225, 381, 36)
// 绘制
ctx.draw();
},
// 绘制头像
drawAvatar(ctx, img, x, y, r) {
ctx.save();
let d = r * 2;
let cx = x + r;
let cy = y + r;
ctx.beginPath()
ctx.arc(cx, cy, r, 0, 2 * Math.PI);
ctx.strokeStyle = '#FFFFFF'; // 设置绘制圆形边框的颜色
ctx.stroke(); // 绘制出圆形,默认为黑色,可通过 ctx.strokeStyle = '#FFFFFF', 设置想要的颜色
ctx.clip();
ctx.drawImage(img, x, y, d, d);
ctx.restore();
},
// 文本n行换行与显示省略号
// 1、canvas对象 2、文本 3、X轴 4、Y轴 5、单行行高 6、文本的宽度
drawtext(ctx, str, axisX, axisY, titleHeight, maxWidth) {
ctx.setFontSize(22); //设置字体字号
ctx.setFillStyle('#000000'); //设置字体颜色
// 文本处理
let strArr = str.split("");
let row = [];
let temp = "";
for (let i = 0; i < strArr.length; i++) {
if (ctx.measureText(temp).width < maxWidth) {
temp += strArr[i];
} else {
i--; //这里添加了i-- 是为了防止字符丢失,效果图中有对比
row.push(temp);
temp = "";
}
}
row.push(temp); // row有多少项则就有多少行
//如果数组长度大于6,现在只需要显示6行则只截取前两项,把第6行结尾设置成'...'
if (row.length > 6) {
let rowCut = row.slice(0, 6);
let rowPart = rowCut[5];
let test = "";
let empty = [];
for (let i = 0; i < rowPart.length; i++) {
if (ctx.measureText(test).width < maxWidth) {
test += rowPart[i];
} else {
break;
}
}
empty.push(test);
// let group = empty[0] //这里只显示两行,超出的用...表示
let group = empty[0] + "..." //这里只显示两行,超出的用...表示
rowCut.splice(5, 1, group);
row = rowCut;
}
// 把文本绘制到画布中
for (let i = 0; i < row.length; i++) {
// 一次渲染一行
ctx.fillText(row[i], axisX, axisY + i * titleHeight, maxWidth);
}
// 保存当前画布状态
ctx.save()
// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。
// ctx.draw()
},
下面是海报下面的分享弹窗
<!-- 分享海报的遮罩层 -->
<view v-if="isShare" class="over_box" @touchmove.stop.prevent="moveHandle"></view>
<!-- 分享海报 -->
<u-popup :show="isShare" @close="closeShare" @open="openShare" mode="bottom" :round="10" :overlay="false">
<view class="trans_box">
<view class="per_box">
<button open-type="share" class="per_but" @click="shareWeixin('WXSceneSession')">
<image :src="getimg('wehcat.png')" style="width:86rpx;height: 86rpx;"></image>
<view class="per_txt">微信好友</view>
</button>
<button class="per_but" @click="shareWeixin('WXSceneTimeline')">
<image :src="getimg('wechat-moments.png')" style="width:86rpx;height: 86rpx;"></image>
<view class="per_txt">朋友圈</view>
</button>
<button @click="saveLocal" class="per_but">
<image :src="getimg('save-poster.png')" style="width:86rpx;height: 86rpx;"></image>
<view class="per_txt">保存图片</view>
</button>
</view>
<view class="share_line"></view>
<view class="close_tran" @click="closeShare">取消</view>
</view>
</u-popup>
因为分享到朋友圈实在没找到有使用自定义按钮的可能,所以还是需要点击右上角胶囊
onLoad(){
//分享功能
wx.showShareMenu({
withShareTicket: true,
//设置下方的Menus菜单,才能够让发送给朋友与分享到朋友圈两个按钮可以点击
menus: ["shareAppMessage", "shareTimeline"]
})
}
//点击分享朋友,朋友圈事件
shareWeixin(scene) {
if (scene == 'WXSceneTimeline') {
uni.showToast({
title: '点击右上角胶囊分享朋友圈',
icon: 'none',
duration: 2000
})
} else {
uni.share({
provider: "weixin",
scene: scene,
type: 0,
href: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',
title: '点子分享',
success(res) {
console.log(res);
},
fail(err) {
console.log(err);
}
})
}
},
onShareAppMessage(res) {
if (res.from === 'button') { // 来自页面内分享按钮
return {
title: 'xxxxxxx', //分享的名称
path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',
mpId: 'wx000000000', //此处配置微信小程序的AppId
imageUrl: ''
}
}
return {
title: 'xxxxx', //分享的名称
path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',
mpId: 'wx0000000000', //此处配置微信小程序的AppId
imageUrl: ''
}
},
//分享到朋友圈
onShareTimeline(res) {
return {
title: this.timeItem,
path: '/pages/index/index',
type: 0,
summary: "",
imageUrl: ''
}
},
以上就是画海报以及分享的全部过程了,另有一个点:
就是分享朋友的地址path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1'
这里这个加个type=1是因为点击分享进入小程序的是个详情页,可能会出现点击左上角返回不能返回首页,所以加上这个type可以在分享页加个判断
onLoad(option) {
if(option.type && option.type==1){ //分享来的页面
this.shareType = 1
}
},
//左上角的点击返回事件加判断,当是分享进入的时候回到首页
goBack(){
if(this.shareType==1){
uni.switchTab({
url:'/pages/index/index'
})
}else{
uni.navigateBack()
this.shareType = 0
}
},