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

最近做项目需求是生成商品分享海报,并且保存到手机中要兼容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. Pymongo 笔记

    Pymongo 1.MongoDB概念 MongoDB是一种非关系型数据库(NoSQL),MongoDB数据存储于内存,内存不足则将热度低数据写回磁盘.存储的数据结构为文档.每个数据库包含若干集合(c ...

  2. HDU 3341 Lost's revenge (AC自动机 + DP + 变进制/hash)题解

    题意:给你些分数串,给你一个主串,主串每出现一个分数串加一分,要你重新排列主串,最多几分 思路:显然这里开$40^4$去状压内存不够.但是我们自己想想会发现根本不用开那么大,因为很多状态是废状压,不是 ...

  3. Dapr 交通控制示例

    Dapr 已在塔架就位 将发射新一代微服务 牛年 dotnet云原生技术趋势 Dapr是如何简化微服务的开发和部署 前面几篇文章都是从大的方面给大家分享Dapr 能帮助我们解决什么问题,微软从开源到1 ...

  4. Laravel Homestead 安装 使用教程详解!

    1 Laravel Homestead 1 安装: 1 下载: http://www.vagrantup.com/downloads.html 1 配置: 1 1 测试: 1 1 ********** ...

  5. 开放式 Web 应用程序安全性项目 OWASP

    开放式 Web 应用程序安全性项目 OWASP Open Web Application Security Project (OWASP) OWASP 基金会是谁? Open Web Applicat ...

  6. HTML5 download 执行条件

    HTML5 download 执行条件 同一个域名下的资源 http only 绝对路径/相对路径 都可以 demo https://cdn.xgqfrms.xyz/ https://cdn.xgqf ...

  7. js & touch & swiper

    js & touch & swiper https://developer.mozilla.org/en/docs/Web/API/Touch_events "use str ...

  8. NGK和USDN的应用

    一.NGK和USDN的发展方向 目前区块链将会朝着两个方向去发展,第一种是金融经济的衍生品,第二种是商业应用,快速支付的货币体系,NGK.IO公链是基于分布式应用设计的商用金融区块链操作系统,通过数字 ...

  9. django学习-23.admin管理后台的数据表数据的自定义展示

    目录结构 1.前言 2.自定义设置一张指定的数据表的列表展示内容 2.1.第一步:如果我们想让数据表[hello_person]里面的表字段值全部展示出来,需在应用[hello]里的[admin.py ...

  10. IO多路复用之select、poll、epoll

    本文转载自IO多路复用之select.poll.epoll 导语 IO多路复用:通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. ...