评论

wxml2canvas-2d:简单易用的小程序海报、战绩等分享图片生成方案

基于微信小程序 2D Canvas 的画布组件,根据给定 WXML 结构以及 CSS 样式快速转换成 Canvas 元素,以用于生成海报图片分享等操作。所见即所得(bushi

Github 地址:https://github.com/ChrisChan13/wxml2canvas-2d

介绍

当前,众多小程序的多处场景都需要能够生成分享图便于用户进行二次传播,从而提升小程序的传播率以及加强品牌效应。
比较简单的分享图,如寥寥几行文字和一张小程序码,可以通过微信的 Canvas API 绘制。旧版 Canvas API 绘制过程繁琐,且每次绘制都需要调用 draw 方法,一不小心代码就写了上百行。
新版 Canvas API 基本与 Web Canvas 对齐,使得开发效率提高、性能得到优化。虽然免去了很多繁琐操作,但面对拥有元素众多、结构复杂的分享图片,依然解决不了代码冗长的问题。
目前开源的一些小程序图片生成方案,有的年久失修、有的依然使用旧版 Canvas API、有的使用方式不够简便,于是便有了开发 wxml2canvas-2d 的想法。
wxml2canvas-2d 的图片生成方式简单直观:首先在 wxml 页面上编写元素结构,其次在 wxss 中编写元素样式,最后调用 wxml2canvas-2d 的相关方法即可生成所需的分享图片。
wxml2canvas-2d 会通过 class 类名查询元素节点的 computedStyle 和节点属性,从而将元素节点绘制到画布上。这样做的好处是在编写 wxml 结构以及样式时,可以直观的看见样式的变化,方便调整。当然也有坏处,这个用来生成图片的“wxml 模板”,必须存在于页面上。若需要隐藏这个“模板”,只可用定位将其移至屏幕外,不可以使用 wx:if 或 hidden 隐藏。
wxml2canvas-2d 已经支持大部分常用的 CSS 属性,等你来测~

示例

克隆此 Github 仓库,运行 npm i & npm run dev,将 miniprogram_dev 文件夹导入微信开发者工具

效果预览

小程序内容:

生成的图片:

安装

npm

使用 npm 构建前,请先阅读微信官方的 npm 支持

# 通过 npm 安装
npm i wxml2canvas-2d -S --production

构建 npm 包

打开微信开发者工具,点击 工具 -> 构建 npm,并勾选 使用 npm 模块 选项,构建完成后,即可引入组件。

使用

  1. 在页面配置中引入 wxml2canvas-2d ;
{
  "usingComponents": {
    "wxml2canvas": "wxml2canvas-2d"
  }
}
  1. 在页面中编写 wxml 结构,将要生成画布内容的根节点用名为 wxml2canvas-container 的样式类名称标记,将该根节点内部需要生成画布内容的节点用名为 wxml2canvas-item 的样式类名称标记(文字类节点需在对应节点声明 data-text 属性,并传入文字内容)。上述两个样式类名称可以自定义,只需将对应名称传入 wxml2canvas 组件的对应属性参数即可;
<!-- pages/index/index.wxml -->
<view class="wxml2canvas-container box">
  <view class="wxml2canvas-item title" data-text="测试标题">测试标题</view>
  <image class="wxml2canvas-item image" src="/your-image-path.png" />
  <view class="wxml2canvas-item content" data-text="测试内容,长文本。。">测试内容,长文本。。</view>
</view>
<button catchtap="generateSharingCard">生成画布内容</button>
<wxml2canvas id="wxml2canvas" />
  1. 补充各个节点样式;
/* pages/index/index.wxss */
.box { /* 根节点(容器)的样式 */ }
.title { /* 标题的样式 */ }
.image { /* 图片的样式 */ }
.content { /* 内容的样式 */ }
  1. 依据 wxml 结构以及 css 样式,生成画布内容,并将生成结果导出。
// pages/index/index.js
Page({
  async generateSharingCard() {
    const canvas = this.selectComponent('#wxml2canvas');
    await canvas.draw();
    const filePath = await canvas.toTempFilePath();
    wx.previewImage({
      urls: [filePath],
    });
  },
});

更多内容及文档 点击此处 前往查看!如果有好的建议或者想法,也欢迎提交 Issue 或 PR~

最后一次编辑于  2024-11-21  
点赞 5
收藏
评论

9 个评论

  • 所有闹钟已关.
    所有闹钟已关.
    04-23

    最近就碰到一个这样的需求 需要把一个页面上的内容导出成图片 研究好久都没做好 主要是页面元素太多了 canvas根本就不好画 用了wxml2canvas插件也是各种报错 直到找到作者这个 使用简单 效果也很棒 真的帮大忙了 为作者点赞!

    04-23
    赞同 1
    回复 20
    • 杰
      04-24
      感谢支持!这是做这个组件的初衷,免去繁琐的 canvas 操作。但组件依然还不够完善,许多样式亟待支持。使用过程中若发现什么问题或需求,欢迎提出探讨~
      04-24
      1
      回复
    • 所有闹钟已关.
      所有闹钟已关.
      04-25回复
      有的样式是不是还不支持呀 比如删除线样式 还有伪类元素
      04-25
      回复
    • 所有闹钟已关.
      所有闹钟已关.
      04-25回复
      还有是不是有的系统也不支持呀 我们老板用的鸿蒙系统 导出来的图片会样式错乱或者直接部分内容消失 不过问题不大安卓跟iOS都没问题
      04-25
      回复
    • 杰
      04-26回复所有闹钟已关.
      非常抱歉,删除线确实没有考虑到,后续会支持的!而伪类元素没办法通过 API 获取对应的节点信息,需要实现的话我能想到的只有通过传 dataset 属性声明该伪类的样式等信息。但这有悖于设计这个组件的初衷,就是:不需要使用额外的大量配置内容,只需要编写节点,就能将其转换为 Canvas 元素。所以目前只好避免使用伪类元素,转而使用真实的节点元素来替代伪类元素。至于鸿蒙系统,先前也有反馈部分鸿蒙的版本会有类似的问题。由于我也没有对应的鸿蒙设备,而且是部分鸿蒙版本会出现的问题,加大了我测试兼容的难度。鸿蒙系统对于部分 API 的兼容程度有限,其系统自身也还在迭代兼容过程,所以再次抱歉目前无法兼容覆盖到一部分鸿蒙版本的设备!
      04-26
      1
      回复
    • 杰
      04-26
      你也可以提供一下能复现绘制出错的代码片段,方便我之后测试兼容!
      04-26
      1
      回复
    查看更多(15)
  • HikW
    HikW
    09-09

    怎么感觉画出来的有点模糊呢?

    09-09
    赞同
    回复 1
    • 杰
      09-11
      默认绘制的尺寸是按照设备的像素比进行缩放,请确认原本内容尺寸是否就较小?若觉得还是较为模糊,可以对组件设置 scale 属性进行放大
      09-11
      回复
  • 雨田
    雨田
    08-08

    鸿蒙5.0得到的是一张纯白图,目前能解决吗

    08-08
    赞同
    回复 1
    • 杰
      08-08
      鸿蒙设备上的小程序目前自身存在的 BUG 也比较多,我目前也没有相关设备,调试难度大,不好排查修复,可能没办法快速得到修复。
      08-08
      回复
  • momo
    momo
    07-30

    data-text里如果加入一些符号就会乱码

    <view class="flx jcb aic cell ">

    <view class="lf wxml2canvas-item" data-text="币种()">币种:()</view>

    <view class="rt wxml2canvas-item" data-text="{{test}}">{{test}}</view>

    </view>

    test: '人民币()'


    07-30
    赞同
    回复 1
    • 杰
      07-30
      哈喽,该问题已在 v1.3.5 中修复!
      07-30
      回复
  • 渺
    07-12

    作者大大,什么时候可以支持map标签也能绘画到canvas

    07-12
    赞同
    回复 2
    • 杰
      07-13
      抱歉呢,map 组件无法支持,map 属于原生组件,没有办法获取到 map 上的内容,官方 skyline 引擎下的 snapshot 组件都不能截取原生组件的内容
      07-13
      回复
    • 渺
      07-14回复
      OK,明白了
      07-14
      回复
  • 雾
    07-07

    如果页面内含有canvas绘制的内容和echarts图表也可以直接使用这个生成图片吗?

    07-07
    赞同
    回复 3
    • 杰
      07-07
      很抱歉,暂时无法生成包含 canvas 的页面内容,需要手动先将 canvas 导出为 image 展示在页面中才可以绘制,不过后续可以考虑将 canvas 内容纳入开发计划~
      07-07
      回复
    • 雾
      07-08回复
      好的
      07-08
      回复
    • 杰
      07-08回复
      哈喽,新版本已发布!支持 canvas 节点和自定义组件的绘制生成图片,如下参考自定义组件绘制所需的设置。生成 echarts 组件的图片,需要对 echart 组件的 wxml 内容进行简单修改。
      07-08
      回复
  • Delete隐身
    Delete隐身
    06-20

    这个可以同时生成多个订单的核销二维码吗?

    06-20
    赞同
    回复 1
    • 杰
      06-20
      当然可以,需要同时截取多张不同的图的话,可以用多个 wxml2canvas 组件,各自为 container-class 以及 item-class 自定义不同的样式类名,并在对应节点的 class 中体现,如:
      06-20
      回复
  • 只为今҈天҈
    只为今҈天҈
    04-17

    模拟器能生成图片但是调试手机的时候无法生成 是需要改什么配置嘛WAServiceMainContext.js:1 MiniProgramError

    Cannot convert undefined or null to object

    TypeError: Cannot convert undefined or null to object

        at t.assign (<anonymous>)

    at (appservice.app.js:64:5525)

        at Array.map (<anonymous>)

    at ComponentCaller.<anonymous> (appservice.app.js:64:5492)

    at (WASubContext.js:1:155925)

    at (WASubContext.js:1:152101)

    at (WASubContext.js:1:155909)

    at (WASubContext.js:1:155717)

    at Function.<anonymous> (WASubContext.js:1:152141)

        at <setTimeout callback function>

    04-17
    赞同
    回复 19
    • 杰
      04-17
      请问可以提供一下代码片段吗?这个报错看不清楚具体位置
      04-17
      回复
    • 只为今҈天҈
      只为今҈天҈
      04-17回复
      就是ni demo的代码贴进去后 真机调试的时候就报错了
      04-17
      回复
    • 只为今҈天҈
      只为今҈天҈
      04-17
      04-17
      回复
    • 只为今҈天҈
      只为今҈天҈
      04-17
      04-17
      回复
    • 只为今҈天҈
      只为今҈天҈
      04-17
      发现俩canvas的打印不一样 模拟器
      Canvas component: li {__data__: {…}, __wxWebviewId__: 4, __wxExparserNodeId__: "8f756b55"}




      真机
      Canvas component: ComponentCaller {}data: (...)dataset: (...)exitState: (...)id: (...)is: (...)pageRouter: (...)properties: (...)renderer: (...)router: (...)[[Prototype]]: ComponentCaller
      04-17
      回复
    查看更多(14)
  • ᓚᘏᗢ 可
    ᓚᘏᗢ 可
    03-17

    经常出现后面的文本没了~~如以下文本:

    高血压(hypertensive disease)是一种以动脉血压持续升高为主要表现的慢性疾病,常引起心、脑、肾等重要器官的病变并出现相应的后果。起病及经过缓慢,最终死亡原因为心衰、肾衰及脑血管意外。本病为最常见的心血管疾病,WHO公布成人高血压患病率高达15%。国内本病患病率约7-10%。随年龄增长,发病有明显上升趋势。黑人、肥胖、吸烟、脑力劳动者等人群发病率较高。长期、系统、正规的抗高血压治疗有助于减慢病情发展、防止靶器官损害及提高生活质室。

    03-17
    赞同
    回复 1
    • 杰
      03-18
      感谢你所指出的问题,该问题已在最新版本中修复!
      03-18
      回复
登录 后发表内容