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 模块 选项,构建完成后,即可引入组件。
使用
- 在页面配置中引入
wxml2canvas-2d
;
{
"usingComponents": {
"wxml2canvas": "wxml2canvas-2d"
}
}
- 在页面中编写 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" />
- 补充各个节点样式;
/* pages/index/index.wxss */
.box { /* 根节点(容器)的样式 */ }
.title { /* 标题的样式 */ }
.image { /* 图片的样式 */ }
.content { /* 内容的样式 */ }
- 依据 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~
最近就碰到一个这样的需求 需要把一个页面上的内容导出成图片 研究好久都没做好 主要是页面元素太多了 canvas根本就不好画 用了wxml2canvas插件也是各种报错 直到找到作者这个 使用简单 效果也很棒 真的帮大忙了 为作者点赞!
模拟器能生成图片但是调试手机的时候无法生成 是需要改什么配置嘛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>
// 获取 canvas 组件实例
const canvas = this.selectComponent('#wxml2canvas');
console.log('Canvas component:', canvas);
// 检查组件实例是否存在
if (!canvas) {
throw new Error('未找到 canvas 组件');
}
// 调用 draw 方法进行绘制
await canvas.draw();
// 获取生成的图片路径
const filePath = await canvas.toTempFilePath();
if (!filePath) {
throw new Error('生成分享图片失败,未返回图片路径');
}
Canvas component: li {__data__: {…}, __wxWebviewId__: 4, __wxExparserNodeId__: "8f756b55"}
真机
Canvas component: ComponentCaller {}data: (...)dataset: (...)exitState: (...)id: (...)is: (...)pageRouter: (...)properties: (...)renderer: (...)router: (...)[[Prototype]]: ComponentCaller
经常出现后面的文本没了~~如以下文本:
高血压(hypertensive disease)是一种以动脉血压持续升高为主要表现的慢性疾病,常引起心、脑、肾等重要器官的病变并出现相应的后果。起病及经过缓慢,最终死亡原因为心衰、肾衰及脑血管意外。本病为最常见的心血管疾病,WHO公布成人高血压患病率高达15%。国内本病患病率约7-10%。随年龄增长,发病有明显上升趋势。黑人、肥胖、吸烟、脑力劳动者等人群发病率较高。长期、系统、正规的抗高血压治疗有助于减慢病情发展、防止靶器官损害及提高生活质室。
您好,我的小程序项目是用的vue+uniapp。请问如何正确引用
你好,想请教下,canvas 画布大小有限制,无法生成超长图片。这个问题有什么解决方案吗?有没有可能不用 canvas,直接使用 JS 生成图片?
1. 将内容分成片段,不超过大小限制,按顺序逐一绘制到 Canvas 上并导出,最后拼成一张完整图片;
2. 使用官方 Skyline 渲染引擎,使用 snapshot 组件,https://developers.weixin.qq.com/miniprogram/dev/component/snapshot.html;
3. 由后端提供图片生成、使用无头浏览器渲染并截图等。
canvas 绘制出文字 + 图片(图1)
1. ctx.getImageData 获取到每个像素的颜色数据 Uint8ClampedArray
2. 拼接图片,将两份数据合并
3. JS 库生成图片数据,高度 * 2
UPNG.encode([bitmapData2.buffer], width, height * 2, 0)
图3 是原始图片尺寸,和每个步骤的结束时间
- 第三方库的合并方法可能有优化空间,删除非必要逻辑
- 运用小程序的多线程 Worker 进行合并,减少主线程阻塞
- 涉及画布的内容使用 OffscreenCanvas,减少主线程阻塞
但做这些优化和测试,有点费时费力
您好,我在Taro框架上使用,文字渲染不出来是什么原因?代码就是示例代码,图片也可以展示,但是文字渲染不出来
// config/index.js
const config = {
plugins: [
[
'@tarojs/plugin-inject',
{
components: {
Text: {
// 'data-text': "'dataText'",
// 'data-text': "dataText",
// 'data-text': "",
},
},
},
],
],
}
在mac设备上生成时会有大部分内容缺失 这是什么原因导致的呢
https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html
请问Uniapp上如何使用?
怎么做
依据 wxml 结构以及 css 样式,生成画布内容,并将生成结果导出。
文字加粗的问题css中的加粗会丢失,该如何解决