项目功能整理:微信小程序生成二维码海报

2,402 阅读5分钟

刚做完一个微信小程序的项目,现在对项目里的一些功能进行整理,这篇文章记录下如何在小程序里实现生成带有二维码的海报,并保存到用户相册。

以此文章记录,便于后续项目使用。

项目是基于mpvue做的。

项目要求

每个用户可以生成一个属于自己的推广二维码,拉新后记录推广人。

生成的海报最终效果也不复杂,如图:

下面保存图片是个白底的按钮,跟背景色混一块就看不到了。。。

需求分析

通过查阅微信小程序的文档得知,可以借助于小程序提供的canvas绘图功能根据设计图来绘制个canvas图,然后通过保存图片到相册这个API把图片保存到用户的手机相册。

海报中有些内容是固定不变的,比如背景图、邀请话术以及下面长按图片的提示语,而还有些内容是动态的,比如用户名和小程序码,不同项目需求不一样,但都会有变动和不变两类内容,然后我们根据设计图一点一点把内容绘制到图上就行啦。

知道要做什么了,那么我们来罗列下要做的事情(吉德林法则有云:把要解决的问题清清楚楚的列下来,问题就解决了一半)

  • 获取用户名
  • 获取用户专属小程序码
  • 图片绘制
  • 处理用户取消保存到相册的授权

动手实现

  1. 首先在页面里插入个canvas标签,并把它的位置调整到界面外。至于为啥是通过控制位置而不是控制显示隐藏,动手试过的兄弟都应该知道,优先级问题。
<canvas class="cv-ct-canvas" canvas-id="cv-pic"></canvas>

.cv-ct-canvas {
  position: absolute;
  left: 800rpx;
  width: 300px;
  height: 500px;
}
  1. 准备用户名、小程序码。因为我这里的背景图也是个远程图片,所以也一并要先下载。
const { tempFilePath: bg } = await this.downloadFile('$(STATICFILE_URL)/prom-share-bg.png')
let name = this.userInfo.NickName;
// 下载图片到本地
const { tempFilePath } = await this.downloadFile(this.qrcodeUrl);

这里要说明下,这个downloadFile方法是把微信的downloadFile方法进行了同步处理,其实很简单,就是用个Promise包裹一下。

  1. 往画布上逐个绘制。
const ctx = wx.createCanvasContext("cv-pic");
// 填充背景色
ctx.setFillStyle("#f8f8f8");
ctx.fillRect(0, 0, 300, 400);
ctx.fill();
ctx.setFillStyle("#ffffff");
ctx.fillRect(0, 400, 300, 100);
ctx.fill();
// 填充背景图
ctx.drawImage(bg, 30, 20, 240, 365);
// 写入名字
ctx.setFontSize(15);
ctx.setFillStyle("#FFF9F0");
ctx.fillText(name, 61, 300);
// 写两行提示
ctx.setFillStyle("#322F30");
ctx.setFontSize(14);
ctx.fillText("长按识别小程序码", 33, 440);
ctx.fillText("超值礼包等你来抢", 33, 465);
// 填充小程序码
ctx.drawImage(tempFilePath, 0, 0, 280, 280, 200, 410, 80, 80);
const that = this;
// 把canvas图保存到临时目录
ctx.draw(false, function() {
  wx.canvasToTempFilePath({
    canvasId: "cv-pic",
    success(res) {
      let url = res.tempFilePath;
      that.savePic = url;
    }
  });
});

在最后用canvasToTempFilePath把图片先保存到了临时目录,并把临时目录的地址赋值给了savePic,因为界面上要展示这个图,所以在界面上会有个Image标签,这个标签的地址就是savePic。

  1. 保存到用户相册,代码比较简单,直接上:
if (!this.savePic) return;
  const that = this;
  wx.saveImageToPhotosAlbum({
    filePath: this.savePic,
    success: function() {
      that.showSaveCode = false;
      wx.showToast({
        title: "保存成功",
        icon: "success",
        duration: 2000
      });
    },
    fail: function () {
      that.getWriteToAlbumSetting()
    }
  });

对于最后这个fail里面的getWriteToAlbumSetting方法,下面作解释。

  1. 处理用户拒绝授权。对于需要用户授权的操作,我们现在是这么处理的:
  • 先在页面data里声明一个变量表示当前用户是否已经授权了,比如这里我声明了canWriteToAlbum用来表示是否可以保存图片到相册。
  • 然后在页面加载时,如在mounted钩子函数里执行一次getWriteToAlbumSetting这个方法,该方法主要是通过wx.getSetting获取当前用户是否已经授权,代码如下:
async getWriteToAlbumSetting() {
  // this.getSetting 方法也是对wx.getSetting的一个同步封装处理
  let status = await this.getSetting('writePhotosAlbum')
  // 因为用户第一次进行操作的时候,授权状态为undefined,只有在明确拒绝过的时候才会是false
  if (status === true || status === undefined) {
    this.canWriteToAlbum = true
  } else {
    this.canWriteToAlbum = false
  }
}
  • 在页面中,根据用户的授权情况,显示表面相同其实不同的操作按钮:
<div class="cv-save" @click="saveToPhotosAlbum" v-if="canWriteToAlbum">保存图片</div>
<div class="cv-save" @click="openAlbumSetting" v-else>保存图片</div>

至于为什么要这么做,当然还是因为小程序的限制啦。如果用户拒绝过授权,再次点击保存按钮,要弹出授权界面,而微信明确要求,弹出授权界面必须是用户直接点击按钮触发,所以只能这样实现了。openAlbumSetting代码如下:

async openAlbumSetting() {
  // 还是对微信API的同步封装
  let status = await this.openSetting('writePhotosAlbum')
  // false表示又拒绝了
  if (status === false) return
  // 只有明确授权了才进行保存到相册的操作
  this.canWriteToAlbum = true
  this.saveToPhotosAlbum()
}

总结

这篇文章除了记录对于生成分享海报的实现外,主要还说明了如何处理用户拒绝授权的情况,这里虽然只说了对于拒绝保存图片的授权,但对于其他操作的授权拒绝处理也可以这样。

第一次写文章,有点乱,以后慢慢练习吧~~~