使用 Painter 通过 Json 配置轻松生成小程序海报图

使用 Painter 通过 Json 配置轻松生成小程序海报图

如果你的小程序需要分享到朋友圈,当前通用做法是利用小程序 Canvas 绘制一张带有小程序二维码的海报图,然后引导用户将海报图保存到本地相册后再分享到朋友圈。

然鹅,小程序的 Canvas 生成方法实现起来较难用且坑多,关于小程序 Canvas 的坑,可以查看此仓库。因此,我们这里用一个三方库 Painter 来实现绘制海报的需求。

Painter

Painter 能轻松通过简单的 Json 配置,绘制海报图,它有以下几点优势:

  • 功能全,支持文本、图片、矩形、qrcode 类型的 view 绘制
  • 布局全,支持多种布局方式,如 align(对齐方式)、rotate(旋转)
  • 支持圆角,其中图片,矩形,和整个画布支持 borderRadius 来设置圆角
  • 性能优化,Painter 对网络素材图片加载实现了一套 LRU 存储机制,不用重复下载素材图片。
  • 容错,因为某些特殊情况会导致 Canvas 绘图不完整。Painter 对此加入了对结果图片进行检测机制,如果绘图出错会进行重绘。

Painter 库的整体架构如下:

painter-minip-1

绘制海报

1.下载 Painter

通过 git 下载 Painter 源代码,并将 components 目录拷贝到自己的项目中。

2.引入 Painter

app.json 文件中作为自定义组件引入。

{
  "usingComponents": {
    "painter": "/components/painter/painter"
  }
}

3.使用 Painter

我们在 index.wxml 中直接使用 painter 组件:

<painter customStyle='position: absolute; left: -9999rpx;' palette="{{data}}" bind:imgOK="onImgOK" bind:imgErr="onImgErr" widthPixels="2000"/>
  • palette 字段作为画图数据的数据源
  • imgOKimgErr 事件来获得成功后的图片,或失败的原因
  • widthPixels 用于设置来强制指定生成的图片的像素宽度,否则,会根据你画布中设置的大小来动态调节,比如你用了 rpx,则在 iphone 6 上会生成 0.5 倍像素的图片。由于 Canvas 绘制的图片像素直接由 Canvas 本身大小决定,此处通过同比例放大整个画布来实现对最后生成的图片大小的调节。

当我们调用生成海报事件时,只需将 Json 数据源 data 赋予 Painter 属性 palette 即可绘制海报图,是的,就是这么简单。点击此处 查看 Painter 更多属性设置。

下方有完整示例代码。

4.海报效果图

painter-minip-2-1

完整代码

全局app.json 或 页面.json

{
  "usingComponents": {
    "painter": "/components/painter/painter"
  }
}

index.wxml

<button type="default" bindtap="handleCreateCanvas">生成海报</button>

<!-- 引入 painter组件  -->
<painter customStyle='position: absolute; left: -9999rpx;' palette="{{data}}" bind:imgOK="onImgOK" bind:imgErr="onImgErr" widthPixels="2000"/>

<!-- 预览海报  -->
<view hidden='{{canvasPreview}}' class='preview'>
  <view class="content">
    <view style="margin-top: 20rpx;">
      <image src='{{canvasUrl}}' mode='widthFix'></image>
    </view>
    <view style="margin-top: 30rpx;">
      <button round type="primary" bindtap="handleSave">保存到相册并分享</button>
    </view>
    <view style="margin-top: 20rpx;">
      <icon size="40" color="#ffffff" name="close" bindtap="onCloseCanvas" />
    </view>
  </view>
</view>

index.js

   /**
   * 生成海报
   */
  handleCreateCanvas() {
    const that = this;

    wx.showLoading({
      title: '生成海报中...',
      mask: true
    })

    // 设置海报数据
    this.setData({
      data: {
        width: `600rpx`,
        height: `1080rpx`,
        background: '#fff',
        borderRadius: '4px',
        views: [{
            type: 'image',
            url: '表示图片资源的地址,本地或网络',
            css: {
              top: '10px',
              right: '20px',
              left: '20px',
              borderRadius: '20px',
              width: '600rpx',
              height: '800rpx'
            }
          },
          {
            type: 'text',
            text: '没有武器,仇恨,和暴力',
            css: {
              left: '20px',
              top: '820rpx',
              fontSize: '18px',
              color: "#262626",
              width: '600rpx',
              maxLines: 2
            },
          },
          {
            type: 'text',
            text: '6.7',
            css: {
              right: '30px',
              top: '580rpx',
              fontSize: '28px',
              fontWeight: 'bold',
              color: "#ffffff"
            },
          },
          {
            type: 'image',
            url: '小程序二维码的地址,本地或网络',
            css: {
              bottom: '35rpx',
              left: "260rpx",
              width: '120rpx',
              height: '120rpx',
            },
          },
          {
            type: 'text',
            text: '分享自 · XX电影',
            css: {
              bottom: '10rpx',
              fontSize: '10px',
              color: '#bfbfbf',
              left: '325rpx',
              align: 'center',
            },
          }
        ],
      }
    })
  },

  /**
  * 生成海报成功
  */
  onImgOK(e) {
    this.setData({
      canvasUrl: e.detail.path,
      canvasPreview: false
    })
    wx.hideLoading()
  },

  /**
  * 生成海报失败
  */
  onImgErr(e) {
    wx.showToast({
      title: '生成海报失败',
      icon: 'none',
      duration: 2000
    })
  },
  
  /**
  * 关闭预览
  */
  onCloseCanvas() {
    this.setData({
      canvasPreview: true
    })
  },
  
  /**
  * 保存海报到相册
  */
  handleSave() {
    wx.saveImageToPhotosAlbum({
       filePath: that.data.canvasUrl,
       success(res) {},
       fail(res) {},
    })
      
  }

index.wxss

.preview {
  width: 100%;
  min-height: 100vh;
  background: rgba(0, 0, 0, 0.7);
  position: absolute;
  z-index: 2;
  top: 0;
}

.preview .content {
  z-index: 99;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

可能还喜欢下面的内容

解决 prerender-spa-plugin 插件无法对 Vue.js SPA 进行预渲染问题

解决 prerender-spa-plugin 插件无法对 Vue.js SPA 进行预渲染问题

解决 iOS 10.3.3 设备越狱后 Cydia 无法联网问题

解决 iOS 10.3.3 设备越狱后 Cydia 无法联网问题

5个简单步骤使用h3lix越狱iOS 10.3.3

5个简单步骤使用h3lix越狱iOS 10.3.3

ins@heyrock