1. 功能描述
使用新版 Canvas 2D 实现微信小程序手写签名功能。(文末附有源码地址)
2. Demo 演示
3. 关键点分析
- 使用新版 canvas 2D 实现,微信小程序官方文档只提供旧版 canvas api,新版 Canvas 2D 定义的属性、方法需要自己去查找 -- canvas 2D MDN 文档。
- 使用微信小程序 API
wx.canvasToTempFilePath
实现保存为图片。 - 需要页面横屏去签名,设置页面 JSON 配置
"pageOrientation": "landscape"
。
4. 功能实现
4.1 添加 canvas 容器元素
添加 canvas 容器元素
<canvas
type="2d"
class="canvas"
catch:touchstart="catchtouchstart"
catch:touchmove="catchtouchmove"
></canvas>
注意:此处的 canvas 容器添加 type='2d'
属性,来声明使用的是新版的 canvas2d。
设置画布容器的宽高
.canvas {
width: 100vw;
height: 100vh;
background-color: #F6F8F8;
}
注意:此处设置的 canvas 元素的宽高和实例化 canvas 时候设置的宽高不一样,这里可以认为仅仅是一个容器,而实例中的宽高才是画布的宽高。
4.2 创建 canvas 实例并初始化画布
initCanvas() {
const {
windowWidth,
windowHeight,
pixelRatio: dpr
} = wx.getSystemInfoSync()
// 创建 canvas 画布上下文
wx.createSelectorQuery()
.select('.canvas')
.node()
.exec(res => {
const canvas = res[0].node
// 设置画布大小
canvas.width = windowWidth * dpr
canvas.height = windowHeight * dpr
// 保存 canvas 实例
this.data.canvas = canvas
// 初始化画布
this.data.ctx = canvas.getContext('2d')
this.data.ctx.textAlign = 'center'
this.data.ctx.font = '240px sans-serif'
this.data.ctx.fillStyle = '#E8EAED'
this.data.ctx.fillText('签名区', canvas.width / 2, 360)
this.data.ctx.scale(dpr, dpr)
})
}
对以上代码进行简单说明:
- canvas 2D 的使用需要显示设置画布的宽和高,小程序中的 canvas 默认宽和高为 300 * 150。因此在这里通过获取整个屏幕的大小,然后适配为设备屏幕的
dpr
,并对画布进行缩放,这样会对 canvas 的展示效果具体到每一个像素。 - 在 canvas 2D 绘制的时候和旧版的 canvas 不同:canvas 2D 只需要
lineTo() > stroke() > moveTo()
即可,不需要显示的调用draw()
方法。
4.3 通过 touch 事件实现
catchtouchstart(e) {
// 判断开始签名
if (this.data.drawCount === 0) {
this.handleClear('emit')
}
const { clientX, clientY } = e.changedTouches[0]
this.data.drawCount++
this.data.ctx.strokeStyle = '#000000'
this.data.ctx.lineWidth = 6
this.data.ctx.lineCap = 'round'
this.data.ctx.lineJoin = 'round'
this.data.ctx.beginPath()
this.data.ctx.moveTo(clientX, clientY)
},
catchtouchmove(e) {
// 签名结束则不执行
if (this.data.drawState === 'stop') return
// 判断有多点触屏,则不执行
if (e.touches.length > 1) return
const { clientX, clientY } = e.changedTouches[0]
this.data.drawState = 'ing'
this.data.ctx.lineTo(clientX, clientY)
this.data.ctx.stroke()
this.data.ctx.moveTo(clientX, clientY)
},
源码地址:canvas 手写签名
参考资料