uniapp 生成商品分享通用海报源码,使用canvas生成海报,圆片加圆角,标题换行显示两排 多余点点,兼容H5端和小程序端。
组件显示代码
<template>
<view>
<uni-popup ref="popup" type="center" class="poster-alert">
<view class="poster"><image :src="poster" @longpress="saveImg"></image></view>
<view class="hm row-center">
<view class="item" @tap="shareWx">
<button open-type="share" class="sharebtn">
<image :src="util.ossimg('button-wechat.png')"></image>
</button>
<text>微信</text>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="item" @tap="saveImg">
<view class="sharebtn"><image :src="util.ossimg('button-save.png')"></image></view>
<text>保存图片</text>
</view>
<!-- #endif -->
</view>
</uni-popup>
</view>
</template>
<script>
export default{
name:'GoodsPoster', //商品分享海报
data(){
return{
poster:'',
}
},
methods:{
show(){
this.$refs.popup.open();
},
close(){
this.$refs.popup.close();
},
//分享微信好友
shareWx(){
},
//保存图片
async saveImg(){
// #ifdef MP-WEIXIN
let that = this;
let imginfo = await uni.getImageInfo({src: that.poster })
if(imginfo[1]){
uni.saveImageToPhotosAlbum({filePath:imginfo[1].path,
success() { that.tips.toast('保存成功') },
fail(rej){ that.tips.toast('保存失败'); }
})
}
// #endif
},
}
}
</script>
<style lang="scss" scoped>
.poster-alert{ width:520rpx;
.poster{ width:520rpx; height:832rpx; overflow: hidden; background:#fff; border-radius:16rpx;}
.hm{ margin-top:60rpx;
.item{ text-align: center; margin:0 60rpx;
.sharebtn{ background:none; border:0; padding:0; width:100rpx; height:100rpx; margin:0 auto; margin-bottom:12rpx;
&:after{display:none;}
image{ width:100rpx; height:100rpx; display:block; }
}
text{ font-size:24rpx; color:#fff;}
}
}
}
</style>
海报生成代码
<template>
<view>
<!--分享海报-->
<goods-poster ref="poster"></goods-poster>
<canvas canvas-id="mycanvas" class="mycanvas"></canvas>
</view>
</template>
<script>
import GoodsPoster from '@/components/Goods/GoodsPoster.vue'
export default{
components:{ GoodsPoster },
data(){
return{
}
},
async onLoad() {
this.create();
},
methods:{
//生成圆形填充图片
//参数:ctx:canvas, img:图片, x:距离X, y:距离Y, r:半径
circleImg(ctx, img, x, y, r) {
ctx.save();
var d =2 * r;
var cx = x + r;
var cy = y + r;
ctx.arc(cx, cy, r, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage(img, x, y, d, d);
ctx.restore();
},
//圆角矩形填充图片
// 参数:ctx: canvas, img:图片地址, x:距离X,y:距离Y, width:宽, height:高,radius:圆角大小
drawRoundRectPath(ctx, img, x, y, width, height, radius) {
ctx.save();
ctx.translate(x, y);
ctx.beginPath(0);
ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
ctx.lineTo(radius, height);
ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
ctx.lineTo(0, radius);
ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
ctx.lineTo(width - radius, 0);
ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
ctx.lineTo(width, height - radius);
ctx.closePath();
ctx.clip();
ctx.drawImage(img,0,0,uni.upx2px(460),uni.upx2px(460));
ctx.restore();
},
// 文字自动换行
// 参数:ctx:canvas, content:文字, drawX:距离X, drawY:距离Y, lineHeight: 行高, lineMaxWidth最大宽度, lineNum: 行数
textPrewrap(ctx, content, drawX, drawY, lineHeight, lineMaxWidth, lineNum) {
var drawTxt = ''; // 当前绘制的内容
var drawLine = 1; // 第几行开始绘制
var drawIndex = 0; // 当前绘制内容的索引
// 判断内容是否可以一行绘制完毕
if(ctx.measureText(content).width <= lineMaxWidth){
ctx.fillText(content, drawX, drawY);
} else {
for (var i = 0; i < content.length; i++) {
drawTxt += content[i];
if (ctx.measureText(drawTxt).width >= lineMaxWidth) {
if (drawLine >= lineNum) {
ctx.fillText(content.substring(drawIndex, i) + '..', drawX, drawY);
break;
} else {
ctx.fillText(content.substring(drawIndex, i + 1), drawX, drawY);
drawIndex = i + 1;
drawLine += 1;
drawY += lineHeight;
drawTxt = '';
}
} else {
// 内容绘制完毕,但是剩下的内容宽度不到lineMaxWidth
if (i === content.length - 1) {
ctx.fillText(content.substring(drawIndex), drawX, drawY);
}
}
}
}
},
//获取图片信息
//微信:要下载远程图片到本地
//H5远程图片时要将图片生成base64位,这个可让后台帮生成base64位,前端生成始终有跨域问题头疼, 另一种是将图片放在static目录
async getimgInfo(path){
// #ifdef MP-WEIXIN
const info = await uni.downloadFile({url:path})
return info;
// #endif
// #ifdef H5
const info = [{},{tempFilePath:'/static/img/p.png'}]
return info;
// #endif
},
//生成海报
async create(){
uni.showLoading({title:'海报生成中...'})
let ctx = uni.createCanvasContext('mycanvas',this);
ctx.fillStyle = "#fff"
ctx.fillRect(0,0,uni.upx2px(520),uni.upx2px(845))
//头像
let head = "https://avatar.csdnimg.cn/8/C/D/0_u012015434.jpg";
let headurl = await this.getimgInfo(head);
headurl = headurl[1].tempFilePath;
this.circleImg(ctx,headurl,uni.upx2px(30),uni.upx2px(30),uni.upx2px(36))
//姓名
ctx.setFontSize(uni.upx2px(28))
ctx.fillStyle = '#000';
ctx.fillText("神夜大侠",uni.upx2px(115),uni.upx2px(55))
//说明
ctx.setFontSize(uni.upx2px(20))
ctx.fillStyle = '#000';
ctx.fillText("这件商品很棒,推荐给你看看",uni.upx2px(115),uni.upx2px(85))
//logo
let logo = "https://avatar.csdnimg.cn/8/C/D/0_u012015434.jpg";
let logourl = await this.getimgInfo(logo);
logourl = logourl[1].tempFilePath;
ctx.drawImage(logourl,uni.upx2px(410),uni.upx2px(35),uni.upx2px(80),uni.upx2px(40))
//商品图
let img = "https://avatar.csdnimg.cn/8/C/D/0_u012015434.jpg";
let imgurl = await this.getimgInfo(img);
imgurl = imgurl[1].tempFilePath;
this.drawRoundRectPath(ctx,imgurl,uni.upx2px(30),uni.upx2px(120),uni.upx2px(460),uni.upx2px(460),uni.upx2px(16));
//商品标题
ctx.setFontSize(uni.upx2px(24))
ctx.fillStyle = '#333';
this.textPrewrap(ctx,"这是商品标题名称商品标题名称",uni.upx2px(30),uni.upx2px(670),uni.upx2px(36),uni.upx2px(250),2);
//价格
ctx.setFontSize(uni.upx2px(22))
ctx.fillStyle = this.config.webColor;
ctx.fillText("¥",uni.upx2px(30),uni.upx2px(760))
ctx.setFontSize(uni.upx2px(36))
ctx.fillStyle = this.config.webColor;
ctx.fillText("58.00",uni.upx2px(50),uni.upx2px(760))
//二维码
let ewm = 'https://avatar.csdnimg.cn/8/C/D/0_u012015434.jpg';
let ewmurl = await this.getimgInfo(ewm);
ewmurl = ewmurl[1].tempFilePath;
ctx.drawImage(ewmurl,uni.upx2px(339),uni.upx2px(620),uni.upx2px(150),uni.upx2px(150))
//扫码购买
ctx.setFontSize(uni.upx2px(20))
ctx.fillStyle = "#333";
ctx.fillText("-扫码购买商品-",uni.upx2px(347),uni.upx2px(800))
ctx.draw();
setTimeout(()=>{
uni.canvasToTempFilePath({
canvasId:'mycanvas',
success:res=>{
this.$refs.poster.poster = res.tempFilePath;
this.$refs.poster.show();
uni.hideLoading();
},
fail:err=>{
this.tips.toast('海报生成失败')
uni.hideLoading();
}
})
},500)
},
}
}
</script>
<style lang="scss" scoped>
.mycanvas{ width:520rpx; height:845rpx; background:#fff; position: fixed; bottom:1000px; border-radius:16rpx;}
</style>