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

最近做项目需求是生成商品分享海报,并且保存到手机中要兼容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. 计算机网络基础篇-ppp协议

    所谓的PPP协议是点对点协议,是目前使用最广泛的数据链路层的协议.大部分用户使用电话线拨号入网的,从用户计算机到ISP的链路所使用的数据链路层协议就是PPP协议. 首先介绍下拨号入网的过程.因特网服务 ...

  2. WSL2+Terminal+VScode配置调试

    最近几天一直想找个方法把VMware虚拟机和远程连接工具MobaXterm这一组配合替换掉,因为每次开启虚拟机操作Ubuntu都需要占用很大的内存,而且要等好久好久才能开启!!!后面还要使用MobaX ...

  3. MDN 文档高级操作进阶教程

    MDN 文档高级操作进阶教程 MDN 文档, 如何优雅的使用 MDN 文档上的富文本编辑器 pre & 语法高亮器 code & note box source code 上传附件 i ...

  4. 微信小程序批量上传图片 All In One

    微信小程序批量上传图片 All In One open-data https://developers.weixin.qq.com/miniprogram/dev/component/open-dat ...

  5. js online playground & web editor

    js online playground & web editor -javascript playgrounds 2019 https://scotch.io/tutorials/7-jav ...

  6. NGK DeFi Baccarat或将推动BGV成为下一个千倍币!

    目前,已经接近2020年年末,但是DeFi的热潮还在持续.近日,DeFi市场传出一道重磅利好消息,便是NGK DeFi去中心化交易系统Baccarat即将上线.届时,将会引起整个区块链市场的又一次震动 ...

  7. NGK.IO新一代高倍币BGV即将登陆交易所

    据悉NGK.IO新一代高倍币BGV已与全球前十大交易所进行深度恰谈,预计在不久的将来会完成上线计划.此次BGV的上线战略布局,将进一步扩大BGV生态,赋予BGV更多的便利性和发展空间.除此之外,NGK ...

  8. go-admin在线开发平台学习-2[程序结构分析]

    紧接着上一篇,本文我们对go-admin下载后的源码进行分析. 首先对项目所使用的第三方库进行分析,了解作者使用的库是否是通用的官方库可以有助于我们更快地阅读程序.接着对项目的main()方法进行分析 ...

  9. 【Azure 云服务】如何从Azure Cloud Service中获取项目的部署文件

    问题描述 在历史已经部署的云服务(Azure Cloud Service)中,如何获取到项目在很久以前的部署包文件呢? 解决办法 1)如果部署云服务是通过门户上传部署包到存储账号中,则可以直接从存储账 ...

  10. DOM及相关操作

    1.背景介绍        什么是DOM?简单地说,DOM是一套对文档的内容进行抽象和概念化的方法, 在现实世界里,人们对所谓的'世界对象模型'都不会陌生,例如,当用'汽车'.'房子'和'树'等名词来 ...