小程序海报绘制方案(原生,Uniapp,Taro)

背景

  1. 小程序海报绘制方案有很多,但是大多数都是基于canvas的,而且都是自己封装的,不够通用,不够灵活,不够简单,不够好用。
  2. 本方使用一个开源的小程序海报绘制,非常灵活,扩展性非常好,仅布局就能得到一张海报。

准备工作

安装依赖,也可以把源码下载到本地,源码地址

shell 复制代码
npm install wxml2canvas

布局

无论哪种方案,布局都是一致的,需要注意一些暂未支持的属性:

  1. 变形:transform,但是节点元素使能读取此属性,但是库不支持,所以不要使用
  2. 圆角,border-radius,同上,不要使用,圆形图片有特定的属性去实现,除此之外无法实现其他类型的圆角

布局示例:

注意,除了uniapp,原生和Taro要使用原生组件的方式绘制canvas,因为Taro不支持data-xx的属性绑定方式,这一点很糟糕

html 复制代码
<!-- 外层wrap用于fixed定位,使得整个布局离屏,离屏canvas暂未支持 -->
<view class='wrap'>
  <!-- canvas id,一会 new 的时候需要 -->
  <canvas canvas-id="poster-canvas"></canvas>
  <view class="container">
    <view data-type="text" data-text="测试文字绘制" class='text'>测试文字绘制</view>
    <image data-type="image" data-src="https://img.yzcdn.cn/vant/cat.jpeg" class='image'></image>
    <image data-type="radius-image" data-src="https://img.yzcdn.cn/vant/cat.jpeg" class='radius-image'></image>
  </view>
</view>

原生小程序

js 复制代码
import Wxml2Canvas from 'wxml2canvas'

Component({
  methods: {
    paint() {
      wx.showLoading({ title: '生成海报' });
      // 创建绘制实例
       const drawInstance = new Wxml2canvas({
        // 组件的this指向,组件内使用必传
        obj: this,
        // 画布宽高
        width: 275,
        height: 441,
        // canvas-id
        element: 'poster-canvas',
        // 画布背景色
        background: '#f0f0f0',
        // 成功回调
        finish: (url) => {
          console.log('生成的海报url,开发者工具点击可预览', url);
          wx.hideLoading();
        },
        // 失败回调
        error: (err) => {
          console.error(err);
          wx.hideLoading();
        },
      });
      // 节点数据
      const data = {
        list: [
          {
            // 此方式固定 wxml
            type: 'wxml',
            class: '.text', // draw_canvas指定待绘制的元素
            limit: '.container', // 限定绘制元素的范围,取指定元素与它的相对位置计算
          }
          {
            // 此方式固定 wxml
            type: 'wxml',
            class: '.image', // draw_canvas指定待绘制的元素
            limit: '.container', // 限定绘制元素的范围,取指定元素与它的相对位置计算
          }
          {
            // 此方式固定 wxml
            type: 'wxml',
            class: '.radius-image', // draw_canvas指定待绘制的元素
            limit: '.container', // 限定绘制元素的范围,取指定元素与它的相对位置计算
          }
        ]
      }
     // 调用绘制方法
     drawInstance.draw(data);
    }
  }
})

Uniapp

uniapp 主要讲Vue3的版本,因为涉及 this,需要获取 this 以及时机

js 复制代码
import {  getCurrentInstance} from 'vue';
// 调用时机 setup内,不能在其他时机
// @see https://github.com/dcloudio/uni-app/issues/3174
const instance = getCurrentInstance();


function paint() {
  uni.showLoading({ title: '生成海报' });
  const drawInstance = new Wxml2Canvas({
    width: 290, // 宽, 以iphone6为基准,传具体数值,其他机型自动适配
    height: 430, // 高
    element: 'poster-canvas', // canvas-id
    background: '#f0f0f0',
    obj: instance,
    finish(url: string) {
      console.log('生成的海报url,开发者工具点击可预览', url);
      uni.hideLoading();
    },
    error(err: Error) {
      console.error(err);
      uni.hideLoading();
    },
  });
  // 节点数据
  const data = {
    list: [
      {
        // 此方式固定 wxml
        type: 'wxml',
        class: '.text', // draw_canvas指定待绘制的元素
      }
      {
        // 此方式固定 wxml
        type: 'wxml',
        class: '.image', // draw_canvas指定待绘制的元素
      }
      {
        // 此方式固定 wxml
        type: 'wxml',
        class: '.radius-image', // draw_canvas指定待绘制的元素
      }
    ]
  }
  // 调用绘制方法
  drawInstance.draw(data);
}

Taro

Taro 比较特殊,框架层面的设计缺陷导致了 Taro 组件增加的 data-xx 属性在编译的时候是会清除的,因此Taro要使用这个库要用原生小程序的方式编写组件。

代码和原生的一样,只是要用原生的方式编写组件,然后在 Taro 中使用。 参考原生的代码,原生小程序js参考这

假设原生组件名为 draw-poster,那么首先需要再Taro的页面中引入这个组件,然后在页面中使用这个组件,然后在组件中使用这个库。

js 复制代码
export default {
  navigationBarTitleText: '',
  usingComponents: {
    'draw-poster': '../../components/draw-poster/index',
  },
};
jsx 复制代码
  const draw = useCallback(() => {
    const { page } = Taro.getCurrentInstance();
    // 拿到目标组件实例调用里面的方法
    const instance = page!.selectComponent('#draw_poster');
    // 调用原生组件绘制方法
    instance.paint();
  }, []);
 return <draw-poster id="draw_poster"/>

总结

对比原生的canvas绘制方案,布局的方式获取节点的方式都是一样的,只是绘制的时候不一样,原生的是直接绘制到canvas上,而这个库是先把布局转换成canvas,然后再绘制到canvas上,所以这个库的性能会比原生的差一些,但是这个库的优势在于布局的方式,不需要自己去计算位置,只需要布局,然后调用绘制方法就可以了,非常方便,而且扩展性非常好,可以自己扩展一些布局方式,比如说flex布局,grid布局等等,这些都是可以的,只需要在布局的时候把布局转换成canvas的布局就可以了,这个库的布局方式是参考的微信小程序的布局方式,所以布局的时候可以参考微信小程序的布局方式,这样就可以很方便的布局了。

相关推荐
px不是xp6 分钟前
微信小程序组件化开发最佳实践
微信小程序·小程序·notepad++
曲江涛6 分钟前
微信小程序 摄像头 授权同页面丝滑调用
微信小程序
喵个咪11 分钟前
Headless 架构优势:内容与展示解耦,一套 API 打通全端生态
前端·后端·cms
小江的记录本14 分钟前
【JEECG Boot】 JEECG Boot——数据字典管理 系统性知识体系全解析
java·前端·spring boot·后端·spring·spring cloud·mybatis
喵个咪17 分钟前
传统 CMS 太笨重?试试 Headless 架构的 GoWind,轻量又强大
前端·后端·cms
chenjingming66619 分钟前
jmeter导入浏览器上按F12抓的数据包
前端·chrome·jmeter
张元清19 分钟前
不用 Server Components 也能做 React 流式 SSR —— 实战指南
前端·javascript·面试
前端技术21 分钟前
ArkTS第三章:声明式UI开发实战
java·前端·人工智能·python·华为·鸿蒙
码小瑞25 分钟前
画布文字在不同缩放屏幕上的归一化
前端