Uniapp绘制海报终极解决方案(微信小程序同样适用)

文章目录

  • Uniapp绘制海报终极解决方案(微信小程序同样适用)
    • 问题原因与分析
    • 解决方案
    • 完整代码

问题原因与分析

背景介绍

在微信小程序开发过程中,我们发现分享只能发送给好友,并没有“分享到朋友圈的功能”

以下是任意小程序点开分享界面的截图

所以我们通常的做法是绘制一个带小程序二维码的海报,然后保存到本地图库

最后引导用户把该张图片分享至朋友圈,朋友看到后扫码即可进入小程序

以下是腾讯新闻小程序解决方案——绘制海报

今天,我们就要实现将指定图片(网络路径)绘制成为海报并保存到用户本地的功能

坐稳,我们现在出发:

我们首先分析下程序中存在的难点痛点

  1. 网络图片需要做本地存储后才能开始绘画
  2. 【重点】网络存在不稳定性,如何保证绘画顺序和期望一致(因为uniapp对大部分接口都做了Promise封装)
  3. 绘制好的图片如何保存至用户本地
  4. 如何处理设备适配问题

针对以上几点,画出设计思路图

设计思路图示

解决方案

万事俱备,撸起袖子开始编码!(以下为编码讲解,文末有完整代码)

  1. 首先编写模板代码

    <template><view class="content"><canvas canvas-id="myCanvas"></canvas><button @click="generateImg">点我</button></view>
    </template>
    

    我们首先定义了一个id为myCanvas的画布,用于绘制我们的海报

  2. 设计绘图队列以及数据结构

    data() {return {drawQueue: //画图队列[{path: 'https://zftsw-oss.oss-cn-hangzhou.aliyuncs.com/5c354e4a710461580958674035.jpg',x: 0,y: 0,width: 600,height: 300,type: 'image',},{path: 'https://zftsw-oss.oss-cn-hangzhou.aliyuncs.com/tmp_cb726c3d5765754dc08ba01c6fa8fa522dff4b08c3aad6d4.jpg',x: 520,y: 20,width: 60,height: 60,type: 'image',},{text: '我是文章标题',size: 32,x: 50,y: 365,type: 'text',},{text: '扫码关注我哟',size: 24,x: 300,y: 365,type: 'text',},],ctx: null, //画布上下文counter: -1, //计数器drawPathQueue: [], //画图路径队列}
    },computed: {myPx() {return this.screenWidth / 750},}
    

    这里简单说一下:drawQueue为待绘制队列,其中path是图片网络路径,xy为坐标,type为区分是绘制图片还是文字,drawPathQueue为处理害的绘图队列,其中每个元素会以index标注绘制顺序

  3. 在App.vue应用加载时获取当前屏幕宽度(也可以使用uniapp内置api:upx2px)

    <script>import Vue from 'vue'export default {onLaunch: function() {console.log('App Launch')uni.getSystemInfo({success: (res)=> {Vue.prototype.screenWidth = res.screenWidth}})},onShow: function() {console.log('App Show')},onHide: function() {console.log('App Hide')}}
    </script><style>/*每个页面公共css */
    </style>
    
  4. 在页面初始化时加载canvas实例

    onLoad() {this.ctx = uni.createCanvasContext('myCanvas', this)
    }
    
  5. 写两个监听器,分别监听处理后的队列生成进度和绘制进度

    watch: {drawPathQueue(newVal, oldVal) {/* 所有元素入队则开始绘制 */if (newVal.length === this.drawQueue.length) {console.log('生成的队列:'+JSON.stringify(newVal));console.log('开始绘制...')for (let i = 0; i < this.drawPathQueue.length; i++) {for (let j = 0; j < this.drawPathQueue.length; j++) {let current = this.drawPathQueue[j]/* 按顺序绘制 */if (current.index === i) {/* 文本绘制 */if (current.type === 'text') {console.log('绘制文本:' + current.text);this.ctx.setFillStyle('#000')this.ctx.setFontSize(current.size * this.myPx)this.ctx.fillText(current.text, current.x * this.myPx, current.y * this.myPx)this.counter--}/* 图片绘制 */if (current.type === 'image') {console.log('绘制图片:' + current.path);this.ctx.drawImage(current.path, current.x * this.myPx, current.y * this.myPx, current.width * this.myPx,current.height * this.myPx)this.counter--}}}}console.log('final counter', this.counter);}},counter(newVal, oldVal) {if (newVal === 0) {this.ctx.draw()/* draw完不能立刻转存,需要等待一段时间 */setTimeout(() => {uni.canvasToTempFilePath({canvasId: 'myCanvas',success: (res) => {console.log('in canvasToTempFilePath');// 在H5平台下,tempFilePath 为 base64console.log('图片已保存至本地:', res.tempFilePath)uni.saveFile({tempFilePath: res.tempFilePath,success: function(res) {console.log('本地保存路径为',res.savedFilePath);}});}})}, 1000)}}
    },
    
  6. 最后添加生成点击事件

    generateImg() {this.counter = this.drawQueue.lengththis.drawPathQueue = []/* 将图片路径取出放入绘图队列 */for (let i = 0; i < this.drawQueue.length; i++) {let current = this.drawQueue[i]current.index = i/* 如果是文本直接放入队列 */if (current.type === 'text') {this.drawPathQueue.push(current)continue}/* 图片需获取本地缓存path放入队列 */uni.getImageInfo({src: current.path,success: (res) => {current.path = res.paththis.drawPathQueue.push(current)}})}/* setTimeout(()=>{console.log(JSON.stringify(this.drawPathQueue));},10000) */
    }
    
  7. 调整样式并测试

    <style lang="scss">page {.content {canvas {width: 600rpx;height: 450rpx;border: 1px solid black;margin: 0 auto;}}}
    </style>
    
  8. 效果图

因为只是demo,图片没有认真找,随意放了几张图片,只要将队列中的图片换成自己想要的图片和小程序二维码即可

完整代码

以下是本示例index.vue下的完整代码

<template>
<view class="content"><canvas canvas-id="myCanvas"></canvas><button @click="generateImg">点我</button></view>
</template><script>export default {data() {return {drawQueue: //画图队列[{path: 'https://zftsw-oss.oss-cn-hangzhou.aliyuncs.com/5c354e4a710461580958674035.jpg',x: 0,y: 0,width: 600,height: 300,type: 'image',},{path: 'https://zftsw-oss.oss-cn-hangzhou.aliyuncs.com/tmp_cb726c3d5765754dc08ba01c6fa8fa522dff4b08c3aad6d4.jpg',x: 520,y: 20,width: 60,height: 60,type: 'image',},{text: '我是文章标题',size: 32,x: 50,y: 365,type: 'text',},{text: '扫码关注我哟',size: 24,x: 300,y: 365,type: 'text',},],ctx: null, //画布上下文counter: -1, //计数器drawPathQueue: [], //画图路径队列}},computed: {myPx() {return this.screenWidth / 750},},onLoad() {this.ctx = uni.createCanvasContext('myCanvas', this)},watch: {drawPathQueue(newVal, oldVal) {/* 所有元素入队则开始绘制 */if (newVal.length === this.drawQueue.length) {console.log('生成的队列:'+JSON.stringify(newVal));console.log('开始绘制...')for (let i = 0; i < this.drawPathQueue.length; i++) {for (let j = 0; j < this.drawPathQueue.length; j++) {let current = this.drawPathQueue[j]/* 按顺序绘制 */if (current.index === i) {/* 文本绘制 */if (current.type === 'text') {console.log('绘制文本:' + current.text);this.ctx.setFillStyle('#000')this.ctx.setFontSize(current.size * this.myPx)this.ctx.fillText(current.text, current.x * this.myPx, current.y * this.myPx)this.counter--}/* 图片绘制 */if (current.type === 'image') {console.log('绘制图片:' + current.path);this.ctx.drawImage(current.path, current.x * this.myPx, current.y * this.myPx, current.width * this.myPx,current.height * this.myPx)this.counter--}}}}console.log('final counter', this.counter);}},counter(newVal, oldVal) {if (newVal === 0) {this.ctx.draw()/* draw完不能立刻转存,需要等待一段时间 */setTimeout(() => {uni.canvasToTempFilePath({canvasId: 'myCanvas',success: (res) => {console.log('in canvasToTempFilePath');// 在H5平台下,tempFilePath 为 base64console.log('图片已保存至本地:', res.tempFilePath)uni.saveFile({tempFilePath: res.tempFilePath,success: function(res) {console.log('本地保存路径为',res.savedFilePath);}});}})}, 1000)}}},methods: {generateImg() {this.counter = this.drawQueue.lengththis.drawPathQueue = []/* 将图片路径取出放入绘图队列 */for (let i = 0; i < this.drawQueue.length; i++) {let current = this.drawQueue[i]current.index = i/* 如果是文本直接放入队列 */if (current.type === 'text') {this.drawPathQueue.push(current)continue}/* 图片需获取本地缓存path放入队列 */uni.getImageInfo({src: current.path,success: (res) => {current.path = res.paththis.drawPathQueue.push(current)}})}/* setTimeout(()=>{console.log(JSON.stringify(this.drawPathQueue));},10000) */}}}
</script><style lang="scss">page {.content {canvas {width: 600rpx;height: 450rpx;border: 1px solid black;margin: 0 auto;}}}
</style>

Uniapp绘制海报终极解决方案(微信小程序同样适用)相关推荐

  1. 计算机毕业设计Python+uniapp扫码点餐微信小程序(小程序+源码+LW)

    计算机毕业设计Python+uniapp扫码点餐微信小程序(小程序+源码+LW) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行 环境配置: Pychram社区版+ pyth ...

  2. uni-app(Vue.js)创建运行微信小程序

    uni-app(Vue.js)创建运行微信小程序 1.全局安装 npm install -g @vue/cli 需要安装node,官方网站,否则提示npm不可用 2.创建uni-app 新建文件夹,选 ...

  3. 计算机毕业设计Python+uniapp在线小说阅读平台微信小程序(小程序+源码+LW)

    计算机毕业设计Python+uniapp在线小说阅读平台微信小程序(小程序+源码+LW) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行 环境配置: Pychram社区版+ ...

  4. UniApp:方法篇:微信小程序海报生成和保存

    UniApp在微信小程序中的Canvas画布操作 画布建立 建立画布 <!-- 禁止画布被拖动 --> <canvas canvas-id="posterid" ...

  5. 微信小程序合成海报_利用微信小程序中Canvas API来合成海报生成组件封装

    每个小程序成型后,一般都会选择生成带菊花码的海报分享出去来吸引更多的流量.下面来介绍下其他的一种实现方式吧 原理:主要利用微信小程序强大的Canvas API来合成,生成后可用wx.canvasToT ...

  6. uniapp手写_【转】uni-app框架纯手写微信小程序开发左侧滑动菜单

    本帖最后由 fengrui99 于 2020-7-22 14:38 编辑 原文来自:在学习的uni-app的微信小程序开发路上慢慢开始不一直依赖插件(但是使用插件是真的香,一直用一直香) 在大佬的指引 ...

  7. golang+uniapp 开发的一套微信小程序电商系统

    caoguohttps://github.com/xxjwxc/caoguo 功能 微信小程序电商平台 后台开发语言 golang gmsechttps://github.com/gmsec/gmse ...

  8. 【uni-app】只支持在微信小程序运行的 导入外部3d模型

    1.解决问题 uniapp 导入3d模型,在微信小程序端运行.只支持在微信小程序端使用,若要支持 h5 和 APP端,可以查看这篇,点击这里 只导入了3d模型,未设置让模型动. 2.导入模型格式 gl ...

  9. 使用uniapp开发的第一个微信小程序

    介绍 微信推出小程序后持续火热,使用方便,不占手机容量,这成为了小程序最大的优势.小程序的使用轻便赢得了大批用户的青睐,很多商家为了运营自己店铺也推出了自己的小程序.对于个人开发者而言,小程序可以通过 ...

最新文章

  1. webstorm配置ESLint 一直
  2. 如何从SQL Server 中取得字段说明
  3. 【Android开发】毛玻璃效果
  4. 使用MyBatis框架时发现的一些小bug
  5. onclick 拼接时如何传递json对象
  6. 检测Web浏览器上的内存泄漏
  7. 解决VMware虚拟机桥接模式无法上网的解决方法 ubuntu
  8. mysql瀑布流布局插件_瀑布流JS插件
  9. 【深度学习】(10) 自定义学习率衰减策略(指数、分段、余弦),附TensorFlow完整代码
  10. wallhaven壁纸下载
  11. 10寸、10.1寸、10.4寸液晶屏解决方案
  12. ssh开启图形界面_xwindow——远程启动linux的图形界面
  13. Busybox实践2:分析busybox文件链接原理并编程模拟实现自己的busybox文件
  14. M2VoC比赛论文——台湾大学
  15. XSS漏洞简单概述--UGa
  16. php征婚段子,婚姻婚礼类阿金短视频脚本段子剧本台词范例抖音快手素材
  17. android 像素宽度转换成cm,android-将像素转换为sp
  18. rv1126接2053_2593双目推流
  19. 基于javaweb+jsp的工作日志管理系统(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot)
  20. C#:实现ADBlock plus(网页广告监测)算法(附完整源码)

热门文章

  1. WampServer环境的搭建
  2. NPM酷库:qs,解析URL查询字符串
  3. 使用 Unity 3D 开发游戏的几个架构设计难点
  4. 基于STM32单片机智能自动伸缩衣架雨滴重量光强温度检测伸缩速度可调-蓝牙版
  5. 基于单片机的晾衣架电路设计(#0210)
  6. 计算机如何考职称英语,计算机专业考职称英语
  7. 盈通rx580游戏高手 bios_女装大佬散热加持,盈通RX590GME-8G D5游戏高手显卡上手
  8. AGV初始篇--(5分钟了解AGV)
  9. tff.learning 模块
  10. Latex使用newcommand实现文中图片公式及section引用格式设置。