uni-app中canvas绘制矩形选框需正确初始化:必须传入this(uni.createCanvasContext('my-canvas', this)),确保canvas-id匹配、在onReady中初始化,适配pixelRatio与CSS缩放计算坐标,并每次绘制前clearRect()、绘制后调用ctx.draw()。

uni-app 中 canvas 绘制矩形选框的正确初始化方式
直接调用 uni.createCanvasContext 但没传第二个参数(组件实例),在小程序真机上会返回 null,导致后续所有绘图操作静默失败。必须显式传入当前 Vue 实例(this):
-
uni.createCanvasContext('my-canvas', this)—— 小程序端必需;H5 端可省略this,但统一加上更稳妥 - 确保
canvas标签有canvas-id="my-canvas",且不能写成id或class - 在
onReady或mounted钩子中初始化,避免 DOM 未就绪时调用
触摸事件坐标需手动缩放适配 canvas 像素比
微信小程序 canvas 的逻辑像素和物理像素不一致(pixelRatio 默认为 2 或 3),touchstart 获取的 clientX/clientY 是屏幕坐标,直接用于 ctx.rect() 会导致矩形偏移、尺寸失真。
- 先用
uni.getSystemInfoSync().pixelRatio获取设备像素比 - 再通过
canvas的宽高属性(非 style 宽高)计算缩放系数:scale = canvasWidth / canvas.style.width - 最终坐标要除以
pixelRatio * scale才能对齐画布坐标系 - 常见错误:只除
pixelRatio忽略了 CSS 缩放,或反过来乘错倍数
绘制动态矩形时别漏掉 ctx.clearRect() 和 ctx.draw()
矩形拖拽过程中需要实时重绘,但 uni-app 的 canvas 不支持自动刷新,每次修改后必须显式触发绘制。
- 开始拖拽(
touchstart):记录起点startX/startY - 拖动中(
touchmove):先ctx.clearRect(0, 0, width, height)清空画布,再重绘底图(用ctx.drawImage()),最后画新矩形 - 结束(
touchend):调用ctx.draw(false, () => {...}),第二个参数是回调,用于确认绘制完成后再保存或提交数据 - 漏掉
ctx.draw()→ 界面无变化;漏掉clearRect()→ 多个残影叠加
多端兼容要注意 type="2d" 属性和 H5 的 canvas 获取方式
微信小程序要求 canvas 标签加 type="2d" 才能启用 2D 上下文;而 H5 端不识别该属性,且需用原生 querySelector + getContext('2d') 获取上下文。
- 模板中统一写:
(小程序有效,H5 忽略) - 逻辑层做平台判断:
if (process.env.VUE_APP_PLATFORM === 'mp-weixin') { ... } else { const canvas = uni.$nextTick(() => document.getElementById('my-canvas')); } - 真机调试时,H5 端若报
getContext is not a function,大概率是 canvas 元素还没挂载到 DOM,需加uni.$nextTick或延时
实际中最容易被忽略的不是画矩形本身,而是坐标系转换和绘制时机——同一套 touch 坐标,在不同设备、不同平台、甚至同个小程序的不同机型上,都要重新校准缩放系数,且每次 draw() 必须等前一次完成才能发起下一次,否则会出现绘制错乱或白屏。











