小程序海报绘制方案(原生,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的布局就可以了,这个库的布局方式是参考的微信小程序的布局方式,所以布局的时候可以参考微信小程序的布局方式,这样就可以很方便的布局了。

相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰8 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy9 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom10 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom10 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试