wxml2Canvas库,可以将指定的wxml节点直接转换成canvas元素,并且保存成海报分享图。
可以在github查看相关的api。
详细的介绍、使用方式、原理等,可阅读以下文章:
我这里简单介绍使用方法:
一、安装
npm install wxml2canvas
如果是原生微信小程序开发,需要构建npm。
二、引入
import Wxml2Canvas from 'wxml2canvas';
三、数据初始化
在页面添加canvas元素
<!-- 此处的canvasStyle后面会讲 -->
<canvas :style="canvasStyle" canvas-id="canvasId" class="canvas"></canvas>
说明: canvasStyle:绑定style的写法是uniapp项目,如原生小程序开发项目需修改。绑定的样式是canvas元素的宽高,后面会说明
canvasId:canvas 组件的唯一标识符
// 此处样式是让canvas元素不在可视范围内
.canvas {
position: fixed;
top: -9999999rpx;
background: #fff;
}
3.1 创建实例
let that = this
let drawImage = new Wxml2Canvas(
{
element: 'canvasId', // canvas节点的id,
obj: that, // 在组件中使用时,需要传入当前组件的this
width: that.wxmlCanvas.width, // 宽高
height: that.wxmlCanvas.height, // 这里的高度要动态获取
background: '#fff', // 默认背景色
progress() {
// 绘制进度
},
async finish(tempFilePath) {
console.log(tempFilePath)
},
error(err) {
console.log(err, 'err')
}
},
// 在组件中使用时,需要传入当前组件的this
that
)
3.2 传入数据
let data = {
//直接获取wxml数据
list: [
{
type: 'wxml',
// 第一个参数是绘制对象的根元素的类名,第二个参数是需要绘制节点的类名
class: '.canvas_ele_limit, .draw_canvas',
limit: '.canvas_ele_limit',// 绘制对象的根元素的类名
x: 0,
y: 0
}
]
}
如上,type声明为wxml时,会查找所有类名为draw_canvas的节点,并且加入到绘制队列中。
class传入的第一个类名(canvas_ele_limit)限定了查询的范围,可以不传,第二个用来指定查找的节点,可以定义为任意不影响样式展现的通用类名。
3.3 绘制
// 在组件中使用时,需要传入当前组件的this
drawImage.draw(data, this)
3.4完整版代码
// uniapp写法
export default {
data(){
绘制对象元素的宽高
wxmlCanvas: {},
// canvas元素的style值
canvasStyle: ""
}
onLoad() {
this.$nextTick(() => {
setTimeout(async () => {
// 获取绘制元素的宽高
const htmlWidthHeight = await this.getWidthHeight('#wxml-canvas')
Object.assign(this.wxmlCanvas, {
width: Math.floor(htmlWidthHeight.width),
height: Math.floor(htmlWidthHeight.height)
})
// 设置canvas元素的宽高
this.canvasStyle = `width: ${htmlWidthHeight.width}px;height: ${htmlWidthHeight.height}px`
setTimeout(() => {
this.draw()
}, 100)
}, 300)
})
},
methods: {
// 获取节点的宽高
getWidthHeight(selector) {
return new Promise((resolve) => {
const query = uni.createSelectorQuery().in(this)
query
.select(selector)
.boundingClientRect((data) => {
return resolve(data)
})
.exec()
})
},
draw() {
let that = this
let data = {
//直接获取wxml数据
list: [
{
type: 'wxml',
// 第一个参数是绘制对象的根元素的类名,第二个参数是需要绘制节点的类名
class: '.canvas_ele_limit, .draw_canvas',
limit: '.canvas_ele_limit',// 绘制对象的根元素的类名
x: 0,
y: 0
}
]
}
//创建wxml2canvas对象
let drawImage = new Wxml2Canvas(
{
element: 'canvasId', // canvas节点的id,
obj: that, // 在组件中使用时,需要传入当前组件的this
width: that.wxmlCanvas.width, // 宽高
height: that.wxmlCanvas.height, // 这里的高度要动态获取
background: '#fff', // 默认背景色
progress() {
// 绘制进度
},
async finish(tempFilePath) {
console.log(tempFilePath)
},
error(err) {
console.log(err, 'err')
}
},
that
)
//传入数据,画制canvas图片
setTimeout(() => {
drawImage.draw(data, that)
}, 30)
},
}
}
四、页面元素的绑定
需要绘制的元素都要表明data-type类型,以及绘制时查找结点的类名draw_canvas
4.1 文字元素
如果是文字,需要给元素绑定data-type="text"和data-text="需要绘制的文字内容。
<view data-type="text" data-text="文字1" class="draw_canvas goods-info__car-calc_item-label">文字1</view>
4.2 图片元素
如果是图片,需要给元素绑定data-type="image"和data-url="图片地址"。
<image data-type="image" data-url="图片地址" class="draw_canvas goods-info__employee-qrcode" src="图片地址"></image>
4.2 页面使用
<view class="box">
<!-- 画图区域 -->
<view id="wxml-canvas" class="canvas_ele_limit">
<view class="draw_canvas poster-wrapper">
<view data-type="text" data-text="文字1" class="draw_canvas goods-info__car-calc_item-label">文字1</view>
<view class="draw_canvas poster-wrapper_top">
<image data-type="image" data-url="图片地址" class="draw_canvas goods-info__employee-qrcode" src="图片地址"></image>
</view>
</view>
</view>
<!-- 画布 -->
<canvas :style="canvasStyle" canvas-id="canvasId" class="canvas"></canvas>
</view>
五、所遇到的问题
绘制失败的原因如下:
5.1 图片保存失败:errorcode:1000
出现如下报错,是图片保存失败
如果调试时,发现获取组件
this,获取元素宽高,以及传递至wxml2Canvas库中的参数都成功了,但是仍然报错:.canvasToTempFilePath: fail canvas is empty,如下图所示:
是因为调用
wxml2Canvas调用wx.canvasToTempFilePath()返回的错误。
此时可能是微信开发者功能版本过高,切换低版本即可解决。
5.2 图片保存失败:errorcode: 1001
如果有使用背景图,即元素设置data-type="background-image",可能会失败。此时将背景图改成图片,就可以解决,即:
<image data-type="image" data-url="图片地址" class="draw_canvas goods-info__employee-qrcode" src="图片地址"></image>
5.3 绘制图片保存至相册会有白边
如图所示:
如果底部是背景色,则可以直接在创建wxml2canvas对象设置background为背景颜色即可。
如果是背景图片,则不可以。
解决方案:
// 设置page元素的width:100%
page {
width: 100%;
height: 100%;
}
// 设置绘制页面的根元素的width:100%
.box {
width: 100%;
}
5.5 网络图片绘制失败:errorcode:1000
如果页面有网络图片,调试源码可知,绘制进度一直在30%,导致出现errorcode:1000的错误。如果此时打开调试工具vconsole,会绘制成功。因为调试状态下,不会有域名限制。出现这种情况就是没有配置白名单的原因。
必须在小程序管理后台配置白名单。
出现问题的原因是:在绘制图片时,使用了wx.getImageInfo方法去获取图片的信息,从文档可知,需要配置白名单。
白名单配置路径:开发=>开发管理=>开发设置=>服务器域名=>downloadFile合法域名