在使用微信小程序开发中,有的需求场景中会需要用户手写签名、或者绘制一些路径,通常会使用 canvas 来实现这种需求
在小程序的开发官方文档中我们可以查找到相关的 canvas 接口使用方法,在文档中我们看到微信官方的提示
2.9.0 起支持一套新 Canvas 2D 接口(需指定 type 属性),同时支持同层渲染,原有接口不再维护。相关api:获取 canvas 实例。
而官方文档中的说明也确实是旧版的 canvas 文档,那么在本文中将详细介绍一下新版和旧版的 canvas 绘制签名的方法
在本例中,使用了小程序的开发框架 mpx, mpx
使用的是微信小程序原生的标签和语法,因此,可以直接将代码复制到项目中进行使用。
使用旧版的 Canvas 接口
介绍一下如何使用旧版的小程序 canvas 接口
- 首先在页面中添加一个 canvas 容器,并添加上相应的时间监听和处理函数
<view class="main">
<canvas canvas-id="custom-canvas" class="canvas" bindtouchstart="onStart" bindtouchmove="onMove" bindtouchend="onEnd"></canvas>
</view>
需要注意的是:此处不能在 canvas 的元素中添加 type=“2d”,如果添加了该属性,则小程序将会把此 canvas 解析为新版本的 canvas2D
-
在脚本中添加处理函数
<script> import { createPage } from '@mpxjs/core' let ctx createPage({ data: {}, methods: { onStart(e) { console.log(e) const [touch] = e.touches const { x, y } = touch ctx.moveTo(x, y) }, onMove(e) { const [touch] = e.touches const { x, y } = touch const point = { x, y } this.draw(point) }, draw(point) { ctx.lineTo(point.x, point.y) ctx.stroke() ctx.draw(true) ctx.moveTo(point.x, point.y) }, onEnd() { console.log('Draw end') }, init() { ctx = wx.createCanvasContext('custom-canvas', this) ctx.setStrokeStyle('#00ff00') // 设置线的宽度 ctx.setLineWidth(5) // 设置线两端端点样式更加圆润 ctx.setLineCap('round') // 设置两条线连接处更加圆润 ctx.setLineJoin('round') } }, onLoad() { this.init() } }) </script>
此处需要注意的是:
-
由于不需要将 canvas 的实例在模板中使用,因此此处将
ctx
声明为了局部变量 -
使用旧版的 canvas 接口,我们可以将初始化过程放在页面挂载的
onLoad
事件中,在初始化过程中通过wx.createCanvasContext
方法创建 canvas 实例,使用框架的时候需要将this
值作为第二个参数传入wx.createCanvasContext
方法中,否则获取不到 canvas 的实例 -
在
touchstart
事件开始的时候,我们需要获取到触摸的起始位置,也就是通过事件中的touches
,该属性返回点击的位置数组,此时我们将 canvas 的起始位置设置到点击位置const [touch] = e.touches const { x, y } = touch ctx.moveTo(x, y)
-
在处理绘制事件的时候,我们一定要按照
lineTo() > stroke() > draw() > moveTo()
的方式来绘制,有的同学就会说了,为什么要再添加一个moveTo()
呢?我们以动图表现一下0-0没有使用
moveTo()
的情况:图中可以看出如果我们移动的过快,就会出现虚线的点
添加了
moveTo()
的效果: -
该旧版接口目前微信小程序已经不再继续维护了,但是如果要适配
v2.9.0
之前的微信版本基础库的话,就需要使用旧版的接口了
-
-
设置画布的大小,此处我设置了整个屏幕的大小
<style lang="stylus"> .canvas { width 100vw height 100vh background-color red } </style>
使用新版的 canvas
微信小程序中新版的 canvas 是基于 Web 标准的 canvas2D 来做渲染的,因此相关的接口文档可以从 MDN 中的 canvas2D 章节中来查看
下面就介绍一下如何使用 canvas2D 来实现签名
<view class="wrapper">
<canvas
wx:ref="SIGNATURE"
class="signature"
disable-scroll="{{true}}"
bindtouchstart="onStart"
bindtouchmove="onMove"
bindtouchend="onEnd"
bindtap="oMouseDown"
type="2d"
>
</canvas>
</view>
注意:此处的 canvas 容器添加了 type="2d"
属性,来声明使用的是新版的 canvas2D
2. 实例化 canvas 实例
import { createPage } from '@mpxjs/core'
let context
createPage({
data: {
listData: ['手机', '电视', '电脑']
},
properties: {
orders: Array
},
methods: {
/**
* 绘制签名
*/
onStart(e) {
console.log(e)
const [touch] = e.touches
const { x, y } = touch
context.moveTo(x, y)
},
onMove(e) {
const [touch] = e.touches
const { x, y } = touch
const point = { x, y }
this.draw(point)
},
cancel(e) {},
tap(e) {},
error(e) {},
onEnd(e) {
this.triggerEvent('signature-touch-end')
},
draw(point) {
context.lineTo(point.x, point.y)
context.stroke()
context.moveTo(point.x, point.y)
},
init() {
this.$refs.SIGNATURE.node((result) => {
const canvas = result.node
context = canvas.getContext('2d')
const { windowHeight, windowWidth, pixelRatio: dpr } = wx.getSystemInfoSync()
canvas.width = windowWidth * dpr
canvas.height = windowHeight * dpr
context.strokeStyle = 'red'
context.lineWidth = 5
context.fillStyle = 'rgba(255, 255, 255, 0)'
context.scale(dpr, dpr)
}).exec()
}
},
ready() {
this.init()
}
})
对以上代码做一下简单说明:
-
由于 canvas2D 的实例需要获取到 canvas 的容器元素,因此我们最早只能在页面
onReady
中调用初始化函数,如果在onLoad
或者onShow
中调用该函数,则无法获取到 canvas 容器元素 -
初始化函数中的
this.$refs.SIGNATURE
是mpx
对小程序的获取元素方法wx.createSelectorQuery()
的包装,因此这里完全可以使用小程序原生的方法获取到 canvas 容器 -
canvas2D 的使用需要显式的设置宽和高,小程序中的 canvas 默认为
300 * 150
的大小,因此在这里我首先获取了整个可用屏幕的大小,然后适配为设备屏幕的dpr
,并对画布进行缩放,这样会对 canvas 的展示效果具体到每一个像素,这也是终极画布的奥秘 -
触摸开始的时候和旧版的canvas 接口是一样的,需要
moveTo
到起始点 -
在 canvas2D 绘制的时候和旧版的 canvas 不同:canvas2D 只需要
lineTo() > stroke() > moveTo()
即可,不需要显式的调用draw()
方法,如下图动图中显式的效果,要不旧版的 canvas 更为细腻
-
设置画布容器的宽高
.wrapper { width 100vw height 100vh display flex justify-context center align-items center } .signature { width 100vw height 100vh margin:0 auto }
注意:此处设置的 canvas 元素的宽高和实例化 canvas 时候的宽和高不一样,这里可以认为仅仅只是一个容器,而实例中的宽和高才是画布的宽高
其他
canvas2D 和 小程序的 canvas 旧版接口中,还提供了清除画布、生成图片等方法,在本文中我们仅展示画布的绘制部分,想要做更深功能的话可以查阅相关文档即可
![](https://img-blog.csdnimg.cn/img_convert/2e0ca51d2474d4e2772d3b391ce79f8a.gif)
更多内容
前端开发转全栈,目前的技术栈是 Node.js、Python,日常研究 C、C++ 和 Rust,孜孜啃食系统开发和网络设计中~
更多的内容请移步GitHub@ruxf,知乎@如小非,掘金@如小非,或者关注我的公众号@全栈开发师,欢迎来撩~
学到老,写到老,生命不停,编程不止~
加油,打工人~