likes
comments
collection
share

uni-app生成带小程序码的分享海报

作者站长头像
站长
· 阅读数 51

canvas中绘制换行的文本

var _self;
// 文字换行
function drawtext(text, maxWidth) {
    let textArr = text.split("");
    let len = textArr.length;
    // 上个节点
    let previousNode = 0;
    // 记录节点宽度
    let nodeWidth = 0;
    // 文本换行数组
    let rowText = [];
    // 如果是字母,侧保存长度
    let letterWidth = 0;
    // 汉字宽度
    let chineseWidth = 21;
    // otherFont宽度
    let otherWidth = 10.5;
    for (let i = 0; i < len; i++) {
        if (/[\u4e00-\u9fa5]|[\uFE30-\uFFA0]/g.test(textArr[i])) {
            if (letterWidth > 0) {
                if (nodeWidth + chineseWidth + letterWidth * otherWidth > maxWidth) {
                    rowText.push({
                            type: "text",
                            content: text.substring(previousNode, i)
                    });
                    previousNode = i;
                    nodeWidth = chineseWidth;
                    letterWidth = 0;
                } else {
                    nodeWidth += chineseWidth + letterWidth * otherWidth;
                    letterWidth = 0;
                }
            } else {
                if (nodeWidth + chineseWidth > maxWidth) {
                    rowText.push({
                            type: "text",
                            content: text.substring(previousNode, i)
                    });
                    previousNode = i;
                    nodeWidth = chineseWidth;
                } else {
                    nodeWidth += chineseWidth;
                }
            }
        } else {
            if (/\n/g.test(textArr[i])) {
                rowText.push({
                        type: "break",
                        content: text.substring(previousNode, i)
                });
                previousNode = i + 1;
                nodeWidth = 0;
                letterWidth = 0;
            } else if (textArr[i] == "\\" && textArr[i + 1] == "n") {
                rowText.push({
                        type: "break",
                        content: text.substring(previousNode, i)
                });
                previousNode = i + 2;
                nodeWidth = 0;
                letterWidth = 0;
            } else if (/[a-zA-Z0-9]/g.test(textArr[i])) {
                letterWidth += 1;
                if (nodeWidth + letterWidth * otherWidth > maxWidth) {
                    rowText.push({
                            type: "text",
                            content: text.substring(previousNode, i + 1 - letterWidth)
                    });
                    previousNode = i + 1 - letterWidth;
                    nodeWidth = letterWidth * otherWidth;
                    letterWidth = 0;
                }
            } else {
                if (nodeWidth + otherWidth > maxWidth) {
                    rowText.push({
                            type: "text",
                            content: text.substring(previousNode, i)
                    });
                    previousNode = i;
                    nodeWidth = otherWidth;
                } else {
                    nodeWidth += otherWidth;
                }
            }
        }
    }
    if (previousNode < len) {
        rowText.push({
            type: "text",
            content: text.substring(previousNode, len)
        });
    }
    return rowText;
}

绘制海报

注意:base64位图片drawImage到canvas上,开发者工具可以正常显示,真机上显示不了,故需要把base64格式图片转本地文件(将Base64的字符串转成ArrayBuffer格式的数据)

1.7.0版本中新增的能力,在本地提供了一个用户文件目录,可以供开发者进行自由的读写操作,通过wx.env.USER_DATA_PATH可以获得这个目录的路径

将Base64的字符串转成ArrayBuffer格式的数据

createPoster() {
    return new Promise((resolve, reject) => {
        uni.showLoading({
                title: '海报生成中'
        });
        const ctx = uni.createCanvasContext('poster');
        let times = 1
        const cavasInfo = {
            bg: '#f6f4f4',
            cavasW: 300 * times, //canvas宽度
            cavasH: 380 * times, //canvas高度
            imgH: 250 * times, //分享图片高度 250
            titleF: 17 * times, //标题字号
            descF: 14 * times, //描述字号
            titleT: 20 * times, //标题距离图片距离
            descT: 30 * times, //描述具体标题高度
            codeT: 18 * times, //扫一扫距离二维码高度
            codeW: 72 * times, //二维码宽高
            codeH: 72 * times,
            leftM: 10 * times, //标题距离左边距离
            // codeL:225, //二维码距离左边距离
            textColor: '#262626', //标题颜色
            muteColor: '#909090' //描述颜色
        }
        ctx.fillRect(0, 0, cavasInfo.cavasW, cavasInfo.cavasH);
        ctx.setFillStyle(cavasInfo.bg);
        ctx.fillRect(0, 0, cavasInfo.cavasW, cavasInfo.cavasH);
        // 图片需先下载到本地才能绘制到canvas上
        uni.downloadFile({
            url: this.bannerImgArr[0].fileUrl,
            success: (res) => {
                if (res.statusCode === 200) {
                    ctx.drawImage(res.tempFilePath, 0, 0, cavasInfo.cavasW, cavasInfo.imgH);
                    // base64位图片drawImage到canvas上,开发者工具可以正常显示,真机上显示不了
                    // 故需要把base64格式图片转本地文件
                    const fsm = wx.getFileSystemManager();
                    const timestamp = Date.parse(new Date()); // 先创建时间戳用来命名(不加时间戳在画连续画第二张图的时候有问题)timestamp: timestamp / 1000
                    const FILE_BASE_NAME = 'tmp_base64' + timestamp; //自定义文件名  因第二张图相同名字读取第一张故加个时间戳
                    console.log(FILE_BASE_NAME)
                   //去掉 base64 的头信息
                    const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(this.shareCodeImg) || [];
                    if (!format) {
                        return (new Error('ERROR_BASE64SRC_PARSE'));
                    }
                    const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
                    //base64 数据转换为 ArrayBuffer 数据
                    const buffer = wx.base64ToArrayBuffer(bodyData);
                    console.log(filePath)
                    //将 ArrayBuffer 数据写为本地用户路径的二进制图片文件
                    fsm.writeFile({
                        filePath,
                        data: buffer,
                        encoding: 'binary',
                        success() {
                                filePath;
                        },
                        fail() {
                                return (new Error('ERROR_BASE64SRC_WRITE'));
                        },
                    });
                    console.log(filePath)
                    console.log(wx.env.USER_DATA_PATH)
                    const basepath = `${wx.env.USER_DATA_PATH}`
                    //此时的图片文件路径在 wx.env.USER_DATA_PATH 中, wx.getImageInfo 接口能正确获取到这个图片资源并 drawImage 至 canvas 上
                    setTimeout(() => {
                        wx.getImageInfo({
                                src: filePath,
                                success: res2=> {
                                        console.log('res2',res2)
                                        // 商品标题
                                        ctx.setFontSize(cavasInfo.titleF);
                                        ctx.setFillStyle(cavasInfo.textColor);
                                        let drawtextList = drawtext(this.data.productName, cavasInfo.cavasW - cavasInfo.codeH);
                                        let textTop = 0;
                                        let titleH = cavasInfo.titleF
                                        console.log('drawtextList', drawtextList)
                                        drawtextList.forEach((item, index) => {
                                                console.log('textTop', textTop)
                                                if (index < 2) {
                                                        textTop = cavasInfo.imgH + cavasInfo.titleT;
                                                        titleH = (index + 1) * cavasInfo.titleF
                                                        ctx.fillText(item.content, cavasInfo.leftM, textTop + titleH);
                                                        console.log('textTop 2', textTop)
                                                }
                                        });
                                        // 商品详情
                                        ctx.setFontSize(cavasInfo.descF);
                                        ctx.setFillStyle(cavasInfo.muteColor);
                                        ctx.fillText(this.data.productNo, cavasInfo.leftM, textTop + titleH + cavasInfo.descT);
                                        // 长按识别二维码访问
                                        ctx.setFontSize(cavasInfo.descF);
                                        ctx.setFillStyle(cavasInfo.muteColor);
                                        let codeL = cavasInfo.cavasW - cavasInfo.codeW - cavasInfo.leftM
                                        ctx.fillText("立即扫一扫", codeL, textTop + cavasInfo.codeH + cavasInfo.codeT);
                                        // 二维码
                                        ctx.drawImage(res2.path, codeL, textTop, cavasInfo.codeW, cavasInfo.codeH);
                                        ctx.draw(true, () => {
                                                // canvas画布转成图片并返回图片地址
                                                uni.canvasToTempFilePath({
                                                        canvasId: 'poster',
                                                        width: cavasInfo.cavasW,
                                                        height: cavasInfo.cavasH,
                                                        success: (res) => {								
                                                                console.log("海报制作成功!", res.tempFilePath);
                                                                resolve(res.tempFilePath);
                                                        },
                                                        fail: () => {
                                                                uni.hideLoading();
                                                                reject();
                                                        }
                                                })
                                        });
                                    },
                                    fail: err => {
                                            uni.hideLoading();
                                            uni.showToast({
                                                    title: '海报制作失败,图片下载失败',
                                                    icon: 'none'
                                            });
                                    }
                                })
                        }, 100);
                } else {
                        uni.hideLoading();
                        uni.showToast({
                                title: '海报制作失败,图片下载失败',
                                icon: 'none'
                        });
                }
            },
            fail: err => {
                    uni.hideLoading();
                    uni.showToast({
                            title: '海报制作失败,图片下载失败',
                            icon: 'none'
                    });
            }
        });
    });
},		

页面弹出分享弹窗,并可保持图片到本地

<canvas canvas-id="poster" class="poster_canvas"></canvas>
<button class="btn share-btn" type="primary" @tap="saveImg()">
    <image src="/static/img/share.png" class="img"></image>分享产品
</button>
<!-- 二维码弹出层 -->
<uni-popup type="center" class="qrcode" ref="qrcode">
    <view class="popup-content">
        <image class="img" :src="posterImg" mode="aspectFit"></image>
        <button class="btn" @click="savePoster">
            <uni-icons class="icon" type="arrowthindown"></uni-icons>保存本地
        </button>
    </view>
</uni-popup>
//调用后台接口生成当前页面的小程序码
getWxShareCode() {
    request({
        url: `/productShare/getUnlimited?page=pages/detail/detail&productId=${this.productId}`,
        success: (res) => {
            console.log('share code success', res)
            // 后台生成的不含base64头的base64位小程序码图片
            let src = res.data.data.img;
            this.shareCodeImg = 'data:image/png;base64,' + src;
        },
        fail: (err) => {
            console.log('share code  err', err);
        }
    });
},
//打开分享弹窗
async saveImg() {
    //生成分享小程序码
    await this.getWxShareCode()
    //绘制生成海报
    let imgUrl = await this.createPoster();
    this.posterImg = imgUrl
    uni.hideLoading();
    //打开弹窗
    this.$refs.qrcode.open()
},
//保存海报到相册
savePoster() {
    console.log('imgUrl', this.posterImg)
    uni.showLoading({
        title: '海报下载中'
    });
    uni.authorize({
        scope: 'scope.writePhotosAlbum',
        success: () => {
            uni.saveImageToPhotosAlbum({
                filePath: this.posterImg,
                success: () => {
                    uni.hideLoading();
                    uni.showToast({
                        title: '保存成功'
                    });
                    this.$refs.qrcode.close()
                }
            });
        }
    });
}

统计分享进入信息

async onLoad(options) {
    this.productId = options.id;
    //解析小程序码得到的参数scene
    //如果有scene,则调用对应接口获取页面具体信息
    if (options.scene) {
        //分享小程序码进入
        let shareInfo = await this.getQrCodeProductInfo(options.scene)
    } else {
        //没有scene参数,则代表不是分享进入小程序的,则调用正常产品接口获取具体信息
        this.getProduct()
    }
},
methods:{
    getQrCodeProductInfo(scene) {
        request({
            url: `/productShare/getQrCodeProductInfo?scene=${scene}`,
            success: (res) => {
                console.log('getQrCodeProductInfo success', res)
                //根据实际具体处理数据
                this.handleProduct(res.data.data)
            },
            fail: (err) => {
                console.log('getQrCodeProductInfo', err);
            }
        });
    }
}
转载自:https://juejin.cn/post/6994343175598899207
评论
请登录