wxml-to-canvas | 微信开放文档 (qq.com)
引入
- 在当前目录的控制台上输入如下代码:
npm install --save wxml-to-canvas
-
点击微信小程序左上角的《工具》->构建npm
注意:若项目之前没有使用过npm管理依赖是无法构建npm的,需要在项目根目录的控制台输入如下代码初始化npm工程。
npm init
- 引入该组件
"usingComponents": {
"wxml-to-canvas": "wxml-to-canvas"
}
- 使用该组件
<wxml-to-canvas class="widget" width="375" height="550"></wxml-to-canvas>
注意点:
- class属性用来标识该组件,可通过设置不同的值来创建不同的wxml-to-canvas组件实例
//在页面js文件中获取该组件实例
onload:function() {
this.widget = this.selectComponent('.widget')
}
-
上面的语句
this.widget = this.selectComponent('.widget')是完成widget对象初始化的,但canvas生成是需要一定时间的,onload函数中widget对象还没有初始化完毕就去调用this.widget.renderToCanvas({wxml,style})将wxml模板和wxss样式绘制到canvas上 的话,会导致页面报如下错: -
解决办法:
进行延迟,给含有this.widget.renderToCanvas({wxml,style})的代码块加一个定时器,500毫秒后再执行,之后就OK了
width和height的值不能省略。
规避点
所有的宽高文字大小使用设计稿大小
如果只需要一次性使用,可以在第一次生成成功之后直接生成图片,然后将图片放在指定位置,根据需要布置图片大小。并移除组件和js缓存。
这样可以减少小程序的性能消耗
renderToCanvas参数必须有wxml和style
调用 this.widget.renderToCanvas({wxml,style}) 必须有wxml和style,最好将wxml 和 style写在方法内,最终返回{wxml,style}
class不能-结尾
wxml中的class如果-结尾会报错
元素要指定width height
每个元素都必须指定 width 和 height 属性,否则会导致布局错误。
文字要写在text组件中
不写在text中无法正常显示
当使用 verticalAlign: 'middle'元素找不到
父元素高30,text元素高30时候,这时是看不到文字的;需要text元素高度也变成40才能看到文字。另外垂直居中也可以使用 lineHeight: 30
不确定文字宽度计算
- 准备工作
- 数据存储格式
viewData: { size: 0, text: '' }- 页面显示
<view class="view-text" style="font-size: {{viewData.size}}px; line-height: {{viewData.size}}px;">{{viewData.text}}</view>- 调用方法
getTextWidth (text, size) { return new Promise((resolve, reject) => { this.setData({ viewData: { size, text } }, () => { wx.createSelectorQuery() .select('.view-text') .boundingClientRect() .exec((res) => { resolve(res[0]) }) }) }) },- 使用方法
const data = await getTextWidth('28.88'.replaceAll('1', '0'), 32) // 因为不能使用行内样式,因此只能给一个class,当遇到循环创建的时候可以给一个下标,使用class="goods-num-0" goodsNum0: {width: data.width},
金额划线价
首先需要用上面方法计算一个宽度,然后通过定位一条灰色的线画到文字中间
读取图片大小
可以通过 wx.getImageInfo() 读取图片大小,进行排版
画边框
当使用borderColor 指定边框颜色的时候,同时背景色也会被指定,这时需要重新设定背景色就好了
文字省略号
计算文字长度,超过部分截取使用...替换
画虚线
未解决,使用切图解决
针对组件速度优化
优化图片生成速度
在调用组件canvasToTempFilePath方法生成图片临时文件时,在其内部调用的是wx.canvasToTempFilePath方法,但是调用方法中的destWidth、destHeight参数是固定的,是canvas大小乘以屏幕的pixelRatio,所以尝试减小输出图片大小优化加载速度。
优化后代码:增加自定义destWidth、destHeight参数
canvasToTempFilePath(args = {}) {
const use2dCanvas = this.data.use2dCanvas
return new Promise((resolve, reject) => {
const {
top, left, width, height
} = this.boundary
const copyArgs = {
x: left,
y: top,
width,
height,
destWidth: args.destWidth || width * this.dpr,
destHeight: args.destHeight || height * this.dpr,
canvasId,
fileType: args.fileType || 'png',
quality: args.quality || 1,
success: resolve,
fail: reject
}
if (use2dCanvas) {
delete copyArgs.canvasId
copyArgs.canvas = this.canvas
}
wx.canvasToTempFilePath(copyArgs, this)
})
}
使用代码
const res = await widget1.canvasToTempFilePath({
destWidth: baseWidth,
destHeight: baseHeight
})
这种方法只有在生成图片大小变小的时候才会有效,因此只在特定场景有效
添加初始化事件
当页面通过selectAllComponents获取了组件,紧接着去调用组件renderToCanvas方法去绘制图片,这时候可能会出现组件内部参数未初始化完成,调用失败的情况,因此需要一个组件加载成功的事件。
如果使用setTimeout方法等待组件完成后再去执行后面的代码,这样可能会导致等待的时间过长,时效性不高。
优化后代码:
if (use2dCanvas) {
const query = this.createSelectorQuery()
query.select(`#${canvasId}`)
.fields({node: true, size: true})
.exec(res => {
const canvas = res[0].node
const ctx = canvas.getContext('2d')
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
this.ctx = ctx
this.canvas = canvas
this.triggerEvent('ready')
})
} else {
this.ctx = wx.createCanvasContext(canvasId, this)
this.triggerEvent('ready')
}
使用代码
<wxml-to-canvas
bind:ready="handleReady"
/>
支持fontWeight
这个文件
这个方法
然后就可以用了
亮点
精确计算文字占用宽度
ctx.measureText(text).width
想要精准计算宽度还要指定字体的样式才可以,比如:
ctx.font = `${fontWeight} ${fontSize}px sans-serif`