微信分享时自定义分享图片

    在开发微信小程序时产品提出了一个需求,就是当用户在阅读一片文章想分享时: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

    // 绘制分享的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

/**
 * @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
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值