内容需求:

小程序端生成一个海报,海报内容包括当前授权账号的头像,当前授权账号的邀请码,一张特定图片,分享页面的带对应参数的小程序二维码;生成的海报需要保存到本地

功能方法:

1.前端用canvas绘图转为图片

2.传相对应的参数 到后端 ,后端用canvas绘图转为图片传给前端

目前我们的项目是多端小程序,百度小程序和微信小程序,因为两端在实际运行的差异所以微信端使用的是前端生成,百度端使用的是后端生成的方式。

具体流程:

在生成海报之前需要根据海报的内容准备对应的图片和文字内容,这样能更稳定快速的生成海报。

!!注意如果绘图过程中使用的图片是网络图片(非本地图片)需要使用uni.getImageInfo方法对图片进行处理!!

!!

由于在获取临时路劲保存图片的时候用一倍的canvas保存的图片会很模糊,我们需要对canvas画布进行多倍处理,一般二倍即可,太大了在Android上可能会出现问题 ,我这里使用的是固定倍数3倍

也可以使用设备的像素比为倍率

  const res = uni.getSystemInfoSync();let  pixelRatio = res.pixelRatio;console.log("该设备的像素比",pixelRatio )

!!

!!在开发过程中还有遇到点小麻烦的就是如何生成对应页面并带对应参数的动态二维码呢?

解决方式是由后端请求微信服务接口 通过配置对应的参数就可以生成一个二维码啦,再将二维码发送给前端就可以了。

涉及的文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/qr-code.html(这里有好几种生成二维码的方法,可以根据自己的业务来调用)!!

<template><canvas :style="{height: pupopHeight + 'px',width: pupopWidth + 'px'}" canvas-id="myCanvas"></canvas><uni-popup   ref="popup" type="center"><view class="popup-wrap"><view class="popup-head">生成海报<view @click="close_popup()" class="close_icon"></view></view><image :src="posterImg" mode=""></image><view  class="popup-footer"><button class="save-btn" @click="saveToLocal()" type="default">保存到相册</button><view class="tips">保存图片到相册,你就可以分享啦!</view></view></view></uni-popup>
</template><script>data(){return{pupopWidth:590,pupopHeight:788,//一定要注意像素密度的问题,这里使用的固定数值pixelRatio:3,//屏幕像数密度inviteQR:'',//动态二维码posterImg:',//最后生成的海报}},mounted(){this.pupopWidth = this.pupopWidth*this.pixelRatiothis.pupopHeight = this.pupopHeight*this.pixelRatioconsole.log("屏幕像素密度",this.pixelRatio,this.pupopWidth,this.pupopHeight)},methods:{//获取当前页面的二维码//这里的做法是传对应的参数到后端,后端生成二位的图片返给前端shareing(){uni.showLoading({title:"海报生成中...",mask:true})//#ifdef MP-WEIXIN//这里参数是前端和后端商议好,生成二维码需要前端传那些对应的值,这里我传了当前页面的路径和邀请码及当前页面的参数let params={page:this.path,scene:this.scene}Api.apiGetCode(params).then(res=>{//去后端请求动态二维码if(res.code === 2000){this.inviteQR = res.data.qrCodePaththis.createPoster();}})//#endif},//生成海报--微信端createPoster(){let _this = this_this.headImg = uni.getStorageSync('avatarUrl')//去本地缓存获取头像uni.getImageInfo({src:_this.headImg,success(image) {const canvasId = "myCanvas"let  ctx = uni.createCanvasContext(canvasId,_this) // 自定义组件中 一定要传this ,这里一开始没加,困惑很久,一定要写一下// 填充背景ctx.setFillStyle('#FFFFFF')ctx.fillRect(0,0,_this.pupopWidth,_this.pupopHeight);ctx.save()// 头像和二维码大小都需要在规定大小的基础上放大像素比的比例后面都会*this.pixelRatiolet headerW = 48 * _this.pixelRatiolet headerX = 40 * _this.pixelRatiolet headerY = 40 * _this.pixelRatio// 控制头像为圆形ctx.setStrokeStyle('rgba(0,0,0,.2)') //设置线条颜色,如果不设置默认是黑色,头像四周会出现黑边框ctx.arc(headerX + headerW / 2, headerY + headerW / 2, headerW / 2, 0, 2 * Math.PI)ctx.stroke()//画完之后执行clip()方法,否则不会出现圆形效果ctx.clip()// 将头像画到画布上         ctx.drawImage(image.path, headerX, headerY, headerW, headerW)ctx.restore()ctx.save()//绘制邀请码const uniqueCode = uni.getStorageSync('uniqueCode') || '';// console.log("uniqueCodeuniqueCode",uniqueCode)let invateCode = `邀请码:${uniqueCode}`let invateCodeX = headerX + headerW + 14 * _this.pixelRatiolet invateCodeY = headerY + headerW/2 + ((26*_this.pixelRatio)/2)ctx.setFontSize(26*_this.pixelRatio);ctx.setFillStyle('#333333');ctx.fillText(invateCode, invateCodeX, invateCodeY);ctx.stroke();//生成banner图uni.getImageInfo({src: _this.banner,//这里的banner是展示的商品图success(image) {let bannerW = 510 * _this.pixelRatiolet bannerH = 255 * _this.pixelRatiolet bannerX = 40 * _this.pixelRatiolet bannerY = 40 * _this.pixelRatio + headerW + 24* _this.pixelRatio// 将banner到画布上ctx.drawImage(image.path, bannerX, bannerY, bannerW, bannerH)ctx.restore()ctx.save()//banner 描述//这里会处理多行显示文字,超出显示省略号的效果let  bannerTextX = 40 * _this.pixelRatiolet bannerTextY = bannerY + bannerH + 20 * _this.pixelRatio  + 50*_this.pixelRatio  //这里的y轴起始值是顶上的距离还要特意加上文字的行高let chr = _this.bannerText.split("");//这个方法是将一个字符串分割成字符串数组let temp = "";let row = [];ctx.setFontSize(30*_this.pixelRatio)ctx.setFillStyle("#333333")for (var a = 0; a < chr.length; a++) {if (ctx.measureText(temp).width < 510 * _this.pixelRatio) {temp += chr[a];}else {a--; //这里添加了a-- 是为了防止字符丢失,效果图中有对比row.push(temp);temp = "";}}row.push(temp); if (row.length > 2) {let rowCut = row.slice(0, 2);let rowPart = rowCut[1];let test = "";let empty = [];for (var a = 0; a < rowPart.length; a++) {if (ctx.measureText(test).width < 510 * _this.pixelRatio) {test += rowPart[a];}else {break;}}empty.push(test);var group = empty[0] + "..."//这里只显示两行,超出的用...表示rowCut.splice(1, 1, group);row = rowCut;}for (var b = 0; b < row.length; b++) {ctx.fillText(row[b], bannerTextX, bannerTextY + b * 50*_this.pixelRatio, 510 * _this.pixelRatio);}//画间隔线ctx.moveTo (40 * _this.pixelRatio, bannerTextY + 40 * _this.pixelRatio + 50*_this.pixelRatio);       //设置起点状态ctx.lineTo (_this.pupopWidth - 40 * _this.pixelRatio,bannerTextY + 40 * _this.pixelRatio + 50*_this.pixelRatio);       //设置末端状态ctx.lineWidth = 1 * _this.pixelRatio;//设置线宽状态ctx.strokeStyle = '#EEEEEE' ;  //设置线的颜色状态ctx.stroke();//二维码uni.getImageInfo({src: _this.inviteQR,success(res){// 画当前页面的二维码const img_x = 40 *_this.pixelRatioconst img_w = 160*_this.pixelRatioconst img_y = _this.pupopHeight - img_w - 40*_this.pixelRatio                          ctx.drawImage(res.path,img_x,img_y,img_w,img_w) //画提示文字const tiptextX = img_x + img_w + 30 * _this.pixelRatioconst tiptext1Y = img_y + (img_w/2)const tiptext2Y = img_y + (img_w/2) + 30 * _this.pixelRatio + 14 * _this.pixelRatioconst tiptext1 = '移居宝'const tiptext2 = '长按识别二维码(微信)'ctx.setFontSize(30*_this.pixelRatio)ctx.setFillStyle("#333333")ctx.fillText(tiptext1, tiptextX, tiptext1Y);ctx.stroke();ctx.setFontSize(26*_this.pixelRatio)ctx.setFillStyle("#666666")ctx.fillText(tiptext2, tiptextX, tiptext2Y);ctx.stroke();ctx.draw(false, () => {uni.canvasToTempFilePath({width: _this.pupopWidth,height: _this.pupopHeight,destWidth: _this.pupopWidth,                           destHeight:_this.pupopHeight,canvasId: canvasId,fileType: 'png',quality:1,success: function(res) {_this.posterImg = res.tempFilePath;//最终将canvas转换为图片_this.$refs.popup.open();uni.hideLoading()},fail(error) {console.log('4',error)toast({msg:'生成海报失败,请稍后重试!'})setTimeout(()=>{uni.hideLoading()},2000)}},_this)})},fail(error) {console.log('获取二维码失败',error)toast({msg:'生成海报失败,获取二维码失败'})setTimeout(()=>{uni.hideLoading()},2000)}})},fail(error) {console.log('生成商品图失败',error)toast({msg:'生成海报失败,获取商品图失败'})setTimeout(()=>{uni.hideLoading()},2000)}});},fail(error) {console.log('生成头像失败',error)toast({msg:'生成海报失败,获取头像失败'})setTimeout(()=>{uni.hideLoading()},2000)}})},
//将图片保存到本地相册
saveToLocal(){//#ifdef MP-WEIXINuni.saveImageToPhotosAlbum({filePath: this.posterImg,success: ()=>{toast({msg:'保存到相册成功'})this.$refs.popup.close()},fail:(err)=>{console.log("保存到相册失败",err)}});//#endif
}
}</script>

总结:

涉及的知识点:

获取带对应参数的二维码,这个需要前后端商议如何对接

uniapp的canvas

uni.canvasToTempFilePath

uni.saveImageToPhotosAlbum

借鉴文章:https://www.jianshu.com/p/266545660eef

uniapp之小程序端生成分享海报(带自定义参数的二维码)相关推荐

  1. Vue页面生成分享海报最详说明(含二维码+多种水印方式+常见的坑处理)

    功能需求: 海报有1张背景图, 海报上的文案内容动态变化 在背景图的某个位置上添加二维码图片 水印功能 大致思路 html页面部分, 包括背景图,接口得来的数据,以及二维码图片的位置 使用 qrcod ...

  2. 微信公众号带场景参数的二维码生成与使用?

    2019独角兽企业重金招聘Python工程师标准>>> 微信公众号推广时,用户通过扫码关注公众号,统计用户是通过哪个带场景二维码进行关注的,并对用户自动分组打标签备注.直接使用微号帮 ...

  3. 如何生成带统计参数的二维码渠道监测

    随着互联网技术的发展,二维码成为App流量分发的主流形式,我们能在各种不同的场合看到扫码入口.这种形式的App推广相较于链接.应用商店而言更加简单灵活,既能打通线上线下的信息通道,也可以植入到图文内容 ...

  4. uniapp微信小程序canvas生成简单海报并下载

    今天项目接到个任务,就是手写canvas海报,并能下载图片.百度了很多海报组件,都不尽人意.萌生了自己手写海报的想法. 话不多说先贴文档 uni-app官网 其实该文档和微信小程序类似 最终效果,微信 ...

  5. 小程序Canvas生成分享海报避坑指南

    关于小程序使用Canvas画布生成分享海报,网上有很多的教程,但是结合到自己的业务上面就BUG百出了 接下来分享一下我的经历 微信出了新的api 微信公众平台目前更新不是太即使,查问题好多帖子都是一两 ...

  6. 微信小程序实现生成分享海报案例

    一.引入插件painter (1)克隆地址:https://gitcode.net/mirrors/Kujiale-Mobile/Painter (2)下载的painter放到小程序的componen ...

  7. 仿商城商品生成分享海报图片和识别图中二维码并跳转商品详情页

    购物商城里面的商品分享给朋友的时候会生成一张海报图片,图片上附带这二维码图片,朋友拿到这张图片扫描上面的二维码就可以进入商品详情页查看此商品了.今天来做一下这种功能,先生成商品海报图片,然后长按这张图 ...

  8. 微信小程序—调用扫一扫功能,通过扫描二维码连接蓝牙模块

    使用微信小程序的扫码功能连接蓝牙,具体操作如下 实现流程图 Created with Raphaël 2.2.0准备好二维码小程序调用扫码功能小程序获取到二维码内容(我这里为蓝牙的名字)小程序通过搜索 ...

  9. 微信小程序 Unexpected token in JSON at position 0 设置二维码,并且使用js中JSON.parse()函数将二维码返回的值转化为json格式

    代码报错: Unexpected token in JSON at position 0 使用二维码生成器, JSON.parse()函数 1.可以随便在网上找一个生成二维码的网站 本人用的是这个 二 ...

最新文章

  1. python中的字符串常用函数
  2. Node.js中模块加载机制
  3. [译]Javascript数列的push和pop方法
  4. SkGradientShader::CreateLinear 的参数。
  5. SpringBoot基础篇日志管理之默认配置
  6. c语言程序计算4阶行列式的值,如何用降阶法求解四阶行列式的计算,请帮我编一个C语言程序。...
  7. PHP 面向对象的简单介绍
  8. linux pxe dhcp 讲解,RHEL 5 PXE+DHCP+NFS+SFTP无人职守网络安装配置
  9. 语义分割数据集——VOC2012
  10. php递归函数详解,php递归函数的调用讲解
  11. css网站常用字体,网站常用字体那些事
  12. centOS安装vnc远程桌面
  13. SPSS进行多元线性回归
  14. 开发者故事|朝九晚六大小周,我就是快乐的技术人
  15. 拨号上网和宽带上网的区别分析
  16. 任意文件读取与下载漏洞
  17. 计算机高考计划,职中高三计算机高考复习计划
  18. 七、VUE基础——悦听音乐播放器案例(vue+axios)
  19. 控制计算机桌面图标,(1)在桌面上显示“计算机”“控制面板”图标,然后隐藏“控制面板”图标。...
  20. 资深电竞发烧友走心盘点,五款高续航游戏低延迟蓝牙耳机分享

热门文章

  1. ubuntu查看本机ip命令
  2. 喜茶门店总数超过650家,深圳单城市突破100家店
  3. 论“黄海和渤海开凿人工运河的分析”(最新)
  4. 10019---层次选择器
  5. 爬虫模拟登录和发表评论
  6. 《Angular之项目启动95%emitting LicenseWebpackPlugin--stop了》
  7. 真 · 前端Vue实战:头条新闻开发项目(下)
  8. APP项目的开发流程
  9. Python爬虫进阶之巧破RSA加密
  10. Nape 碰撞检测事件 笔记