在开发微信小程序时产品提出了一个需求,就是当用户在阅读一片文章想分享时:1.分享时的背景需要和当前页面文章展示的背景一致(文章展示时背景是随机的)。2:分享时分享的封面中的文案要和当前文章有关联,就是分享时封面的标题需要和当前用户看到的文章标题一致。3:当用户点击了分享的卡片,文章展示的背景要和分享时的封面背景一致。
需求解决方案分析:
1 . 分享时使用文章的封面作为分享时的封面
当时第一想到的解决方案就是使用文章的封面作为分享时的图片,但是这样会给文章的编写带来很大压力,每一篇文章都设计一个封面 这个显然是不现实的,当文章大量上架时估计UI该骂街了,而且还面临一个问题就是 分享时的图片要求的是5:4的比例 而我们文章封面是16:9 的封面显示也不适合作为分享的封面使用,所以这张解决方案很快就被pass,就算上这样实现了后期被推翻的可能性很大。
2 . 使用canvas 绘制出分享时的封面
正当一筹莫展时看到 微信的api 中的 imageUrl 参数
onShareAppMessage(Object object)
imageUrl 自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。
那我们可不可以使用canvas 绘制出分享时的封面,再通过api 得到一个临时的图片地址imageUrl的参数呢?经过一番尝试,发现是可以的。
index.wxml
定义一个5:4 的 canvas,这里要注意的时由于canvas 的层级很高,而我们绘制页面时又不想让用户看到这个 canvas 这时我们可以给这个canvas 设置定位将位置设置到屏幕以外
<canvas type="2d" id="share" canvas-id="share" style="width: 750rpx;height: 600rpx;"></canvas>
index.wxss
#share {
position: absolute;
top: -100000rpx;
}
index.js文章来源:https://www.toymoban.com/news/detail-696665.html
// 绘制分享的canvas
_setShareImg() {
let query = wx.createSelectorQuery()
query.select('#share')
.fields({
node: true,
size: true
})
.exec(async (res) => {
// Canvas 对象
const canvas = res[0].node
// 渲染上下文
const ctx = canvas.getContext('2d')
// Canvas 画布的实际绘制宽高
const width = res[0].width
const height = res[0].height
canvas.width = width;
canvas.height = height;
console.log(canvas.width, canvas.height);
// 将背景图片绘制在canvas上
await drawImageToCanvas.call(canvas, this.data.randomColor.bgUrl, 0, 0, width, height);
// 绘制 健康百科 的圆角背景
ctx.beginPath()
ctx.fillStyle = '#2CBEAC'; // 设置填充颜色
ctx.fillRect(getPositonX(70, width), getPositonY(50, height), getPositonX(150, width), getPositonY(50, height));
// 封装方法 绘制 健康百科
fillText.call(ctx, "健康百科", "#fff", getPositonX(30, width), getPositonX(68 + 18, width), getPositonY(60, height))
// 封装方法 绘制 都是您想知道的 杏林药安出品
fillText.call(ctx, "都是您想知道的 ~ 杏林药安出品", "#848484", getPositonX(34, width), getPositonX(70, width), getPositonY(122, height))
// 限制标题最大的显示字数
let title = this.data.title;
if (title.length > 27) {
title = title.substr(0, 23) + '...'
}
// 封装方法将文本分割成 固定数量 并返回集合数组
const textArr = TextToArray(title, 9);
const TextH = 206,
lineH = 100;
textArr.forEach((item, index) => {
// 这里调用两遍是为了实现字体加粗的效果 绘制时错开了 0.5px
fillText.call(ctx, item.join(""), "#333", getPositonX(70, width), getPositonX(70, width), getPositonY(TextH + lineH * index, height))
fillText.call(ctx, item.join(""), "#333", getPositonX(70, width), getPositonX(70 - 0.5, width), getPositonY(TextH + lineH * index - 0.5, height))
})
//
this.setData({
shareUrl: await canvasToTempFilePath(canvas)
})
})
},
onShareAppMessage() {
return {
title: '杏林药安,专注药学服务!',
path: `/pages/plunge/index?
// randomIndex 当前随机颜色的索引
entityid=${this.data.entityid}&randomIndex=${this.data.randomIndex}`,
imageUrl: this.data.shareUrl
}
},
utils.js文章来源地址https://www.toymoban.com/news/detail-696665.html
/**
* @deprecated 将一段字符串分割为 固定长度为一组的数组
* @param {String} textString
* @param {Number} len
*/
function TextToArray(textString, len) {
var textArr = textString.split("");
return textArr.reduce((pre, next, index, arr) => {
return pre.concat([arr.splice(0, len)])
}, []);
}
// canvas中绘制带圆角的矩形
function 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();
}
/**
*
* @param {String} text 文字
* @param {String} color 字体颜色
* @param {Number} fontSize 字号
* @param {Number} pX X坐标
* @param {Number} pY Y坐标
* @param {Number} maxWidth 最大宽度
* @param {String} textBaseline 基线
* @param {String} fontStyle 字体
* 运行两次fillText,x,y的值一次为 (x-0.5,y),一次为 (x,y-0.5),打出来的会变粗
*/
function fillText(text, color, fontSize, pX, pY, maxWidth = 690, textBaseline, fontStyle) {
this.fillStyle = color;
this.textBaseline = textBaseline ? textBaseline : "top" // 文本基线是 em 方框的顶端
this.font = `${fontSize}px ${fontStyle?fontStyle:"PingFangSC-Semibold, PingFang SC"}`; //设置字体
this.fillText(text, pX, pY, maxWidth ? maxWidth : 690); //填充文字
}
/**
* 将canvas 转成临时图片地址
* @param {String} canvas id
*/
function canvasToTempFilePath(canvas) {
return new Promise((resolve, reject) => {
wx.canvasToTempFilePath({
canvas,
fileType: "jpg",
quality: 1,
success(res) {
resolve(res.tempFilePath)
},
fail() {
reject(false)
}
})
})
}
/**
* 将图片绘制在canvas
* @param {String} url 图片路径
* @param {Number} pX x 坐标
* @param {Number} pY y 坐标
* @param {Number} width 宽度
* @param {Number} height 高度
*/
function drawImageToCanvas(url, pX, pY, width, height) {
return new Promise((resolve, reject) => {
const headerImg = this.createImage();
headerImg.src = url; //微信请求返回头像
headerImg.onload = () => {
this.getContext('2d').drawImage(headerImg, pX, pY, width, height);
resolve()
}
})
}
module.exports = {
TextToArray,
drawRoundRectPath,
fillText,
canvasToTempFilePath,
drawImageToCanvas
}
到了这里,关于微信分享时自定义分享图片的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!