uni-app 点击生成海报

前端生成海报兼容H5和小程序

最近做项目需求是生成商品分享海报,并且保存到手机中要兼容H5和小程序

与后端同学沟通后,海报在前端生成最省性能和有较好的交互体验,先看做好的效果

源码地址
在这里插入图片描述

在这里插入图片描述

前端框架使用的是uni-app方便打包成H5和小程序

实现方案是拿到后端返回的数据后,利用canvas画布把各个数据拼在一起并且生成一张图片

主要的参数有:背景图、商品图、二维码、价格、原价、标题

首先拿到产品图和二维码之后需要把它们下载下来用uni-app的api就可以

先写一个下载方法并且在 template 定义画布组件

<template>
 
<canvas class="canvas" canvas-id="myCanvas" v-if="canvasStatus"></canvas>
 
</template>
 
onReady(){
 
  this.downloadFileImg('','pic');
 
  this.downloadFileImg('','code');
 
},
 
methods:{
 
  downloadFileImg(url,name){
 
    let self = this
 
    uni.downloadFile({
 
      url: url,
 
      success: function(res) {
 
        self[name] = res.tempFilePath;
 
      },
 
      fail: function(erros) {
 
        console.log(error)
 
      }
 
    });
 
  }
 
}

这样图片就暂时保存到本地临时文件了

uni.downloadFile 需要注意的是

在各个小程序平台运行时,网络相关的 API 在使用前需要配置域名白名单。在h5上是跨域的,用户需要处理好跨域问题。

下来编写canvas生成图片的方法


/**
    * 获取分享海报
    * @param array imgArr 海报素材 0 背景图 1商品图 2二维码
    * @param string store_name 素材文字
    * @param string price 价格
    * @param string ot_price 原始价格
    * @param function successFn 回调函数
*/
 
PosterCanvas: function(imgArr, store_name, price, ot_price, successFn) {
 
    let that = this;
 
    uni.showLoading({
 
        title: '海报生成中',
 
        mask: true
 
    });
 
    const ctx = uni.createCanvasContext('myCanvas');
 
    ctx.clearRect(0, 0, 0, 0);
 
 
 
    /**
    * 只能获取合法域名下的图片信息,本地调试无法获取
    * 
    */
 
    ctx.fillStyle = '#fff';
 
    ctx.fillRect(0, 0, 750, 1150);
 
    uni.getImageInfo({
 
        src: imgArr[0],
 
        success: function(res) {
 
            const WIDTH = res.width;
 
            const HEIGHT = res.height;
 
            ctx.drawImage(imgArr[1], 0, 0, WIDTH, WIDTH);
 
            ctx.save();
 
            let r = 110;
 
            let d = r * 2;
 
            let cx = 480;
 
            let cy = 790;
 
            ctx.arc(cx + r, cy + r, r, 0, 2 * Math.PI);
 
            // ctx.clip();
 
            ctx.drawImage(imgArr[2], cx, cy, d, d);
 
            ctx.restore();
 
            const CONTENT_ROW_LENGTH = 20;
 
            let [contentLeng, contentArray, contentRows] = that.textByteLength(store_name, CONTENT_ROW_LENGTH);
 
            if (contentRows > 2) {
 
                contentRows = 2;
 
                let textArray = contentArray.slice(0, 2);
 
                textArray[textArray.length - 1] += '……';
 
                contentArray = textArray;
 
            }
 
            ctx.setTextAlign('left');
 
            ctx.setFontSize(36);
 
            ctx.setFillStyle('#000');
 
            // let contentHh = 36 * 1.5;
 
            let contentHh = 36;
 
            for (let m = 0; m < contentArray.length; m++) {
 
                if (m) {
 
                    ctx.fillText(contentArray[m], 50, 1000 + contentHh * m + 18, 1100);
 
                } else {
 
                    ctx.fillText(contentArray[m], 50, 1000 + contentHh * m, 1100);
 
                }
 
            }
 
            ctx.setTextAlign('left')
 
            ctx.setFontSize(72);
 
            ctx.setFillStyle('#DA4F2A');
 
            ctx.fillText('¥' + price, 40, 820 + contentHh);
 
 
 
            ctx.setTextAlign('left')
 
            ctx.setFontSize(36);
 
            ctx.setFillStyle('#999');
 
            ctx.fillText('¥' + ot_price, 50, 876 + contentHh);
 
            var underline = function(ctx, text, x, y, size, color, thickness, offset) {
 
                var width = ctx.measureText(text).width;
 
                switch (ctx.textAlign) {
 
                    case "center":
 
                        x -= (width / 2);
 
                        break;
 
                    case "right":
 
                        x -= width;
 
                        break;
 
                }
 
 
 
                y += size + offset;
 
                ctx.beginPath();
 
                ctx.strokeStyle = color;
 
                ctx.lineWidth = thickness;
 
                ctx.moveTo(x, y);
 
                ctx.lineTo(x + width, y);
 
                ctx.stroke();
 
            }
 
            underline(ctx, '¥' + ot_price, 55, 865, 36, '#999', 2, 0)
 
            ctx.setTextAlign('left')
 
            ctx.setFontSize(28);
 
            ctx.setFillStyle('#999');
 
            ctx.fillText('长按或扫描查看', 490, 1030 + contentHh);
 
            ctx.draw(true, function() {
 
                uni.canvasToTempFilePath({
 
                    canvasId: 'myCanvas',
 
                    fileType: 'png',
 
                    destWidth: WIDTH,
 
                    destHeight: HEIGHT,
 
                    success: function(res) {
 
                        uni.hideLoading();
 
                        successFn && successFn(res.tempFilePath);
 
                    }
 
                })
 
            });
 
        },
 
        fail: function(err) {
 
            uni.hideLoading();
 
            that.Tips({
 
                title: '无法获取图片信息'
 
            });
 
        }
 
    })
 
}

首先创建一个canvas 画布

获取背景图图片信息拿到宽和高再绘制商品图片并保存

接下来绘制二维码并把坐标放好并保存

在处理文字换行问题并设置大小颜色和对其方式

在相对应的设置价格和原价的颜色和大小还有坐标

由于价格还有条横线,我在网上又搜下了横线的做法直接看方法就行

最后生成图片信息并且使用uni.canvasToTempFilePath 方法把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径。

这样我们就得到一个.png的临时文件现在就剩最后一步把文件渲染到组件里了,从回调函数就可以回去到

此方法用的比方比较多我把它写到公共方法里面并且绑定到vue原型上面方便我们后面使用

现在编写方法调用

handelCanvas(){
 
    let imgArr = ['背景图路径',this.pic,this.code]
 
    this.$util.PosterCanvas(imgArr,'标题','价格','原价',function(tempFilePath){
 
        console.log(tempFilePath)
 
    })
 
}

这样就拿到生成好的图片的是一个临时文件 现在把他放到页面中展示就ok了

保存图片功能H5可以长按保存图片这里只用处理小程序的就行

首先检测授权拿到授权后调用uni-app的api就可以了

savePosterPath: function() {
 
    let that = this;
 
    uni.getSetting({
 
        success(res) {
 
            if (!res.authSetting['scope.writePhotosAlbum']) {
 
                uni.authorize({
 
                    scope: 'scope.writePhotosAlbum',
 
                    success() {
 
                        uni.saveImageToPhotosAlbum({
 
                            filePath: 'canvas生成的临时图片',
 
                            success: function(res) {
 
                                ....成功了
 
                            },
 
                            fail: function(res) {
 
                                ....失败了
 
                            }
 
                        });
 
                    }
 
                });
 
            } else {
 
                uni.saveImageToPhotosAlbum({
 
                    filePath: 'canvas生成的临时图片',
 
                    success: function(res) {
 
                        ....成功了
 
                    },
 
                    fail: function(res) {
 
                        ....失败了
 
                    }
 
                });
 
            }
 
        }
 
    });
 
}

这样前端生成海报就大功告成了,你学废了吗?

开源代码

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值