- A+
### 移动端分享海报生成
最近做项目需求是生成商品分享海报,并且保存到手机中要兼容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框架目前已经适配