### 移动端分享海报生成

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

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

前端框架使用的是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) {

                        ....失败了

                    }

                });

            }

        }

    });

},

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

最后打一波广告:

CRMEB商城一个免费开源项目

移动端使用uni-app框架目前已经适配公众号、小程序、app(暂未发布)

管理后台使用vue+iview框架

开源不易,希望各位关注下,说不定你会有意外收获!

地址:http://github.crmeb.net/u/qiang

前端生成分享海报兼容H5和小程序的更多相关文章

  1. Vue生成分享海报(含二维码)

    本文已同步到专业技术网站 www.sufaith.com, 该网站专注于前后端开发技术与经验分享, 包含Web开发.Nodejs.Python.Linux.IT资讯等板块. 功能需求: 海报有1张背景 ...

  2. MpVue 致力打造H5与小程序的代码共用

    MpVue是什么 基于 Vue.js 的小程序开发框架 从底层支持 Vue.js 语法和构建工具体系. 使用vue开发小程序 修改了 Vue.js 的 runtime 和 compiler 实现,使其 ...

  3. 移动端学习之理解WEB APP、Native APP、Hybrid APP以及React Native/uniapp包括H5、小程序等的区别与共通之处

    因为工作需要,需要进一步了解移动端的开发,遂返回复习移动端的知识点,在开始学习之前,产生了疑惑WEB APP .Native APP .Hybrid APP.React Native.Uniapp.H ...

  4. 仅以一个前端开发人员的角度看微信小程序

    看了几天的小程序(当然也包括了上手书写),才有了这篇博文,非技术贴,只是发表下个人观点,仅以个人技术能力来看小程序. 首先说下优点: 调试工具:官方的工具还是做了很多工作,包括监听文件变动自动刷新,编 ...

  5. 记录一些移动端H5,小程序视觉还原问题及方法

    前端,特别是移动端如果对视觉还原要求比较高的时候.功能测试和性能测试完成之后.UI真的是一个像素一个像素的给你抠出来哪里还原不到位 之前项目要求还原度要达到98%以上.所以每到视觉还原的时候真的是挺痛 ...

  6. 小程序内嵌H5——判断小程序环境的坑

    现在各种小程序风靡,这边H5的需求还没有搞定,产品又要求做小程序版本,做可以,关键是618前上线,我-- whatever,618要做推广,日期订了,剩下的就只能是排期,定方案,尽可能完成. 最后和产 ...

  7. uniapp 在h5和小程序上使用高德获取用户城市位置

    开发文档 https://lbs.amap.com/api 错误状态 https://lbs.amap.com/api/webservice/guide/tools/info/ 虽然用的高德但是你还需 ...

  8. h5与小程序互相跳转,传参和获取参数

    1.h5跳转到小程序 首先引入js文件 <script src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js">< ...

  9. uni-app开发经验分享二十: 微信小程序 授权登录 获取详细信息 获取手机号

    授权页面 因为微信小程序提供的 权限弹窗 只能通用户确认授权 所以可以 写一个授权页面,让用户点击 来获取用户相关信息 然后再配合后台就可以完成登录 <button class="bt ...

随机推荐

  1. 进程控制——fork-and-exec、system、wait

    forc-and-exec流程 父进程与子进程之间的关系十分复杂,最大的复杂点在于进程间相互调用.Linux下这一流程称为fork-and-exec.父进程通过fork的方式产生一个一模一样的子进程, ...

  2. GitHub rename the default branch from master to main

    GitHub rename the default branch from master to main master => main Repository default branch Cho ...

  3. how to design a search component in react

    how to design a search component in react react 如何使用 React 设计并实现一个搜索组件 实时刷新 节流防抖 扩展性,封装,高内聚,低耦合 响应式 ...

  4. alipay 小程序开发教程

    alipay 小程序开发教程 https://opendocs.alipay.com/mini/00ccmd 或访问开放平台:https://opendocs.alipay.com/mini/00cc ...

  5. how to check a var whether is number in js

    how to check a var whether is number in js js check var is number Number.isInteger(NaN) false Number ...

  6. 1. VUE介绍

    今天开始系统学习vue前端框架. 我是有前端基础的, 刚工作那会, 哪里分那么清楚啊, 前后端我都得做, 所以, css, js, jquery, bootstrap都会点, 还系统学过ext, 哈哈 ...

  7. [Android搞机]修改build.prop解决类原生无法链接12、13信道wifi问题

    最近xda找包刷了个机,发现没法搜到12.13信道.所有未本地化的类原生都有此问题. root后打开/system/build.prop 可以用 在build.prop中加入以下几句,重启即可连接12 ...

  8. Example之selectOneByExample方法和selectByExample的使用

    selectOneByExample示例如下: Example userExample = new Example(User.class);userExample.createCriteria().a ...

  9. <span>居中

    在父元素中加style="text-align:center"; 比如下面这样 <head> </head> <body>     <di ...

  10. wxWidgets源码分析(8) - MVC架构

    目录 MVC架构 wxDocManager文档管理器 模板类创建文档对象 视图对象的创建 创建顺序 框架菜单命令的执行过程 wxDocParentFrame菜单入口 wxDocManager类的处理 ...