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

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

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

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

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

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

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

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

  1. <template>
  2. <canvas class="canvas" canvas-id="myCanvas" v-if="canvasStatus"></canvas>
  3. </template>
  4. onReady(){
  5.   this.downloadFileImg('','pic');
  6.   this.downloadFileImg('','code');
  7. },
  8. methods:{
  9.   downloadFileImg(url,name){
  10.     let self = this
  11.     uni.downloadFile({
  12.       url: url,
  13.       success: function(res) {
  14.         self[name] = res.tempFilePath;
  15.       },
  16.       fail: function(erros) {
  17.         console.log(error)
  18.       }
  19.     });
  20.   }
  21. }

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

uni.downloadFile  需要注意的是

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

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

  1. /**
  2.     * 获取分享海报
  3.     * @param array imgArr 海报素材 0 背景图 1商品图 2二维码
  4.     * @param string store_name 素材文字
  5.     * @param string price 价格
  6.     * @param string ot_price 原始价格
  7.     * @param function successFn 回调函数
  8. */
  9. PosterCanvas: function(imgArr, store_name, price, ot_price, successFn) {
  10.     let that = this;
  11.     uni.showLoading({
  12.         title: '海报生成中',
  13.         mask: true
  14.     });
  15.     const ctx = uni.createCanvasContext('myCanvas');
  16.     ctx.clearRect(0, 0, 0, 0);
  17.     /**
  18.     * 只能获取合法域名下的图片信息,本地调试无法获取
  19.     * 
  20.     */
  21.     ctx.fillStyle = '#fff';
  22.     ctx.fillRect(0, 0, 750, 1150);
  23.     uni.getImageInfo({
  24.         src: imgArr[0],
  25.         success: function(res) {
  26.             const WIDTH = res.width;
  27.             const HEIGHT = res.height;
  28.             ctx.drawImage(imgArr[1], 0, 0, WIDTH, WIDTH);
  29.             ctx.save();
  30.             let r = 110;
  31.             let d = r * 2;
  32.             let cx = 480;
  33.             let cy = 790;
  34.             ctx.arc(cx + r, cy + r, r, 0, 2 * Math.PI);
  35.             // ctx.clip();
  36.             ctx.drawImage(imgArr[2], cx, cy, d, d);
  37.             ctx.restore();
  38.             const CONTENT_ROW_LENGTH = 20;
  39.             let [contentLeng, contentArray, contentRows] = that.textByteLength(store_name, CONTENT_ROW_LENGTH);
  40.             if (contentRows > 2) {
  41.                 contentRows = 2;
  42.                 let textArray = contentArray.slice(0, 2);
  43.                 textArray[textArray.length - 1] += '……';
  44.                 contentArray = textArray;
  45.             }
  46.             ctx.setTextAlign('left');
  47.             ctx.setFontSize(36);
  48.             ctx.setFillStyle('#000');
  49.             // let contentHh = 36 * 1.5;
  50.             let contentHh = 36;
  51.             for (let m = 0; m < contentArray.length; m++) {
  52.                 if (m) {
  53.                     ctx.fillText(contentArray[m], 50, 1000 + contentHh * m + 18, 1100);
  54.                 } else {
  55.                     ctx.fillText(contentArray[m], 50, 1000 + contentHh * m, 1100);
  56.                 }
  57.             }
  58.             ctx.setTextAlign('left')
  59.             ctx.setFontSize(72);
  60.             ctx.setFillStyle('#DA4F2A');
  61.             ctx.fillText('¥' + price, 40, 820 + contentHh);
  62.             ctx.setTextAlign('left')
  63.             ctx.setFontSize(36);
  64.             ctx.setFillStyle('#999');
  65.             ctx.fillText('¥' + ot_price, 50, 876 + contentHh);
  66.             var underline = function(ctx, text, x, y, size, color, thickness, offset) {
  67.                 var width = ctx.measureText(text).width;
  68.                 switch (ctx.textAlign) {
  69.                     case "center":
  70.                         x -= (width / 2);
  71.                         break;
  72.                     case "right":
  73.                         x -= width;
  74.                         break;
  75.                 }
  76.                 y += size + offset;
  77.                 ctx.beginPath();
  78.                 ctx.strokeStyle = color;
  79.                 ctx.lineWidth = thickness;
  80.                 ctx.moveTo(x, y);
  81.                 ctx.lineTo(+ width, y);
  82.                 ctx.stroke();
  83.             }
  84.             underline(ctx, '¥' + ot_price, 55, 865, 36, '#999', 2, 0)
  85.             ctx.setTextAlign('left')
  86.             ctx.setFontSize(28);
  87.             ctx.setFillStyle('#999');
  88.             ctx.fillText('长按或扫描查看', 490, 1030 + contentHh);
  89.             ctx.draw(true, function() {
  90.                 uni.canvasToTempFilePath({
  91.                     canvasId: 'myCanvas',
  92.                     fileType: 'png',
  93.                     destWidth: WIDTH,
  94.                     destHeight: HEIGHT,
  95.                     success: function(res) {
  96.                         uni.hideLoading();
  97.                         successFn && successFn(res.tempFilePath);
  98.                     }
  99.                 })
  100.             });
  101.         },
  102.         fail: function(err) {
  103.             uni.hideLoading();
  104.             that.Tips({
  105.                 title: '无法获取图片信息'
  106.             });
  107.         }
  108.     })
  109. },

首先创建一个canvas 画布

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

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

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

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

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

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

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

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

现在编写方法调用

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

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

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

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

  1. savePosterPath: function() {
  2.     let that = this;
  3.     uni.getSetting({
  4.         success(res) {
  5.             if (!res.authSetting['scope.writePhotosAlbum']) {
  6.                 uni.authorize({
  7.                     scope: 'scope.writePhotosAlbum',
  8.                     success() {
  9.                         uni.saveImageToPhotosAlbum({
  10.                             filePath: 'canvas生成的临时图片',
  11.                             success: function(res) {
  12.                                 ....成功了
  13.                             },
  14.                             fail: function(res) {
  15.                                 ....失败了
  16.                             }
  17.                         });
  18.                     }
  19.                 });
  20.             } else {
  21.                 uni.saveImageToPhotosAlbum({
  22.                     filePath: 'canvas生成的临时图片',
  23.                     success: function(res) {
  24.                         ....成功了
  25.                     },
  26.                     fail: function(res) {
  27.                         ....失败了
  28.                     }
  29.                 });
  30.             }
  31.         }
  32.     });
  33. },

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

最后打一波广告:

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. Apple & 人体工程学

    Apple & 人体工程学 https://support.apple.com/zh-cn/HT205655 MBP 2018 https://help.apple.com/macbookpr ...

  2. VSCode Plugin & Auto File Header Comments Generator

    VSCode Plugin & Auto File Header Comments Generator Xcode SwiftUI // // ContentView.swift // Mem ...

  3. element ui 停止维护了

    ️‍♂️ element ui 停止维护了 最近看到有人说 element ui 已经停止维护了,还有点不相信; 不过到 github 验证一下,好像是真的呀 4 个月,没有任何更新了 https:/ ...

  4. Flutter & QRCode App

    Flutter & QRCode App https://github.com/xgqfrms/qrcode-reader-app how to open android emulator o ...

  5. flutter 让app跟随系统的theme

    首先你需要在"MaterialApp"设置两套theme MaterialApp( theme: myTheme, // light darkTheme: ThemeData.da ...

  6. NGK算力持有好处多多!SPC、VAST等免费拿!

    众所周知,NGK是分布式存储的,作为Web3.0以及数字经济时代的基础设施,为数字加密市场带来了全新的商业模式和经济业态,但是,这只是一个重要的起点,真正的价值还在后面! 为了满足NGK生态建设者强烈 ...

  7. NGK公链有发展前景吗?

    最近网络中经常能看到一个新公链项目NGK的消息,很多朋友也都私下表示过,非常看好今年的NGK.对此,小编对NGK做了一些功课,发觉到NGK未来在商业Dapp应用的发展前景,下面就给大家分享一下我的理解 ...

  8. Github Packages和Github Actions实践之CI/CD

    概述 Github在被微软收购后,不忘初心,且更大力度的造福开发者们,推出了免费私有仓库等大更新.近期又开放了packages和actions两个大招,经笔者试用后感觉这两个功能配合起来简直无敌. G ...

  9. 生产者和消费者问题(synchronized、Lock)

    1.synchronized的生产者和消费者 synchronized是锁住对象 this.wait()释放了锁 并等待 this.notify()随机通知并唤醒同一个对象中的一个线程 this.no ...

  10. QT实现输入框与下拉框提示并可模糊匹配

    功能:支持下拉框选择.手动输入更改和模糊匹配 组件:QLineEdit.QComboBox.QCompleter.QStringListModel 一.组件介绍 1.1 QLineEdit QLine ...