前言
在微信小程序开发中,canvas组件常用于实现图表绘制、图片裁剪、签名板等功能。相比于旧版的 canvas 接口,小程序基础库 2.9.0 起开始支持的Canvas 2D 接口性能更好,且与 Web 标准更加接轨。
本文将带领大家从零开始,实现一个基于 Canvas 2D 的自由绘图画板,并在此基础上扩展一个实用功能:动态切换画笔颜色。
一、 核心知识点
Canvas 2D 组件:使用
<canvas type="2d">标签。节点查询 (SelectQuery):通过
wx.createSelectorQuery()获取 canvas 节点及上下文。触摸事件:利用
bindtouchstart和bindtouchmove获取手指坐标并绘制。绘图 API:
ctx.beginPath(),ctx.lineTo(),ctx.stroke(),ctx.clearRect()等。
二、 项目结构与布局设计
首先,在index.wxml中搭建页面结构。我们需要一个画布区域以及底部的操作按钮。
html
<!--index.wxml--> <view class="box"> <view class="title">自由绘图</view> <!-- Canvas 2D 组件,绑定触摸事件 --> <canvas type="2d" id="my-canvas" bindtouchstart="paintStart" bindtouchmove="paintMove" /> <view class="btn-layout"> <!-- 清空按钮 --> <button type="primary" size="mini" bindtap="clear">清空画布</button> <!-- 扩展功能:改变颜色按钮 --> <button type="warn" size="mini" bindtap="changeColor">改变画笔颜色</button> </view> </view>
接着,在app.wxss或index.wxss中添加一些基础的样式,让界面看起来更加美观:
css
/**app.wxss**/ .box { margin: 20rpx; padding: 20rpx; border: 2rpx solid purple; } .title { font-size: 40rpx; font-weight: bolder; text-align: center; margin-bottom: 30rpx; color: red; } /* 设置画布大小,必须指定具体像素 */ canvas { width: 100%; height: 600rpx; background-color: cornflowerblue; /* 初始画布背景色 */ } .btn-layout { display: flex; justify-content: space-around; margin-top: 20rpx; }三、 核心逻辑实现 (index.js)
这是整个案例的核心部分。我们需要在页面加载完成后(onReady)初始化 Canvas,并在触摸事件中处理绘图逻辑。
1. 初始化 Canvas 与获取上下文
在小程序中,我们必须通过wx.createSelectorQuery来获取真实的 canvas 节点。
javascript
Page({ data: { currentColor: '#ff0000' // 默认画笔颜色:红色 }, onReady() { // 创建查询对象 const query = wx.createSelectorQuery() // 选择 id 为 my-canvas 的节点 query.select('#my-canvas') .fields({ node: true, size: true }) .exec((res) => { const canvas = res[0].node const ctx = canvas.getContext('2d') // 处理设备像素比,防止绘图模糊 const dpr = wx.getSystemInfoSync().pixelRatio canvas.width = res[0].width * dpr canvas.height = res[0].height * dpr ctx.scale(dpr, dpr) // 将 canvas 和 ctx 挂载到 this 上,方便其他函数调用 this.canvas = canvas this.ctx = ctx // 初始设置画笔样式 ctx.lineWidth = 4 ctx.lineCap = 'round' ctx.lineJoin = 'round' }) }, // ... 后续方法 })2. 实现自由绘制 (TouchStart & TouchMove)
paintStart:手指按下时,记录起始点,并开启一个新路径。
paintMove:手指移动时,不断连接坐标点并绘制。
javascript
paintStart(e) { let ctx = this.ctx if (!ctx) return // 开启新路径 ctx.beginPath() // 获取触点坐标 (注意:小程序新版接口推荐使用 e.touches[0].x 或 clientX) let x = e.touches[0].x let y = e.touches[0].y // 将画笔移动到起始点 ctx.moveTo(x, y) }, paintMove(e) { let ctx = this.ctx if (!ctx) return let x = e.touches[0].x let y = e.touches[0].y // 动态应用当前的颜色 ctx.strokeStyle = this.data.currentColor // 画线到当前坐标 ctx.lineTo(x, y) // 执行绘制 ctx.stroke() }3. 扩展功能:清空画布与切换颜色
clear:使用
clearRect擦除整个画布区域。changeColor:在红、绿、蓝三种颜色之间循环切换,并更新 data 中的状态。
javascript
clear() { let canvas = this.canvas let ctx = this.ctx if (!canvas || !ctx) return // 开启新路径(避免之前的路径影响) ctx.beginPath() // 清空整个画布矩形区域 ctx.clearRect(0, 0, canvas.width, canvas.height) }, // 扩展功能:改变画笔颜色 changeColor() { let color = this.data.currentColor let newColor = '' // 颜色轮换逻辑:红 -> 绿 -> 蓝 -> 红 if (color === '#ff0000') { newColor = '#00ff00' } else if (color === '#00ff00') { newColor = '#0000ff' } else { newColor = '#ff0000' } // 更新页面数据 this.setData({ currentColor: newColor }) }四、 效果展示与总结
完成代码编写后,运行小程序,效果如下:
初始状态:画布为蓝色背景,默认画笔为红色,可以自由书写。
颜色切换:点击“改变画笔颜色”按钮后,画笔颜色变为绿色/蓝色,继续书写即可看到效果。
清空画布:点击“清空画布”按钮,画板恢复初始空白状态。
开发踩坑提示:
模糊问题:在手机上运行时,如果不乘以设备的
pixelRatio进行缩放,画出来的线条会非常模糊(发虚)。代码中的ctx.scale(dpr, dpr)是解决此问题的关键。坐标获取:部分旧版开发工具可能获取不到
e.touches[0].x,此时可以尝试兼容写法(如e.touches[0].clientX)。但在最新基础库的 Canvas 2D 模式下,直接使用x和y属性即可。样式设置顺序:
ctx.strokeStyle等样式设置最好放在ctx.stroke()调用之前。
通过这个小案例,不仅掌握了小程序 Canvas 2D 的基本绘图流程,还学会了如何结合数据绑定(setData)来实现绘图属性的动态更新,希望能为你的小程序开发之路提供帮助!