Canvas签名不响应触摸事件,主因是未正确绑定事件或未设宽高;图片模糊因未适配dpr;导出失败因上下文不匹配或绘制未完成;背景异常因未清空填充。
真机调试时签名区域完全没反应,或者只在部分区域生效——大概率是 canvas 组件没正确绑定触摸事件或未设置宽高。uni-app 的 canvas(尤其是 2D 上下文)在不同平台行为差异大,H5 和小程序对 touchstart/touchmove 的处理逻辑也不同。
实操建议:
canvas-id + type="2d" 声明 canvas,并在 onReady 后通过 uni.createCanvasContext 获取上下文,不要用 querySelector 或直接操作 DOMtouchstart/touchmove 事件并调用 ctx.moveTo/ctx.lineTo;小程序端可直接用 bindtouchstart/bindtouchmove 属性,但要确保事件对象里能拿到 touches[0].x/y
style 中加 touch-action: none 防止 iOS Safari 默认滚动拦截导出的 PNG 图片在手机上看起来发虚、线条断续,不是因为分辨率低,而是 canvas 像素比(dpr)没适配。uni-app 的 canvas 默认以 1:1 渲染,而 iPhone 和安卓高端机 dpr 多为 2 或 3,导致绘制点被拉伸模糊。
实操建议:
uni.getSystemInfoSync().pixelRatio 获取设备 dpr,再将 canvas 的 width 和 height 属性设为「设计宽高 × dpr」,同时用 CSS 将 canvas 样式宽高设为原始设计尺寸(如 375×200px)ctx.scale(dpr, dpr),让所有坐标和线宽自动按比例缩放ctx.lineWidth = 1 这类固定值,应设为 1 / dpr,否则高 dpr 下线条会过粗调用 uni.canvasToTempFilePath 后回调不触发、报错 canvas is not found,或生成的临时文件路径为空——这是最常踩的坑,核心原因是 canvas 实例与导出 API 不在同一上下文,或 canvas 尚未完成绘制就调用了导出。
实操建议:
ctx.stroke() 执行完),再调用 uni.canvasToTempFilePath;可在 setTimeout 中延后 16ms(一帧)再执行,避免渲染队列未 flushcanvasId 和当前页面的 this 实例(即 success 回调里的 res.tempFilePath 才有效),H5 端则要用 canvas.toDataURL('image/png') 替代uni.createSelectorQuery().select('#myCanvas').fields({ node: true, size: true }),确保 node 存在且 width/height > 0导出的图片本该是白底黑线,结果全是黑底,或关键线条消失——这是因为 canvas 默认背景透明,而某些平台(尤其 Android 微信)在导出时把 alpha 通道当成了黑底合成。
实操建议:
ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, width, height);,注意这个 width/height 是 canvas 元素的逻辑宽高(非像素宽高)canvasToTempFilePath 的 fileType 必须显式设为 'png',jpg 不支持透明uni.getImageInfo 检查临时文件是否加载成功,再用 uni.uploadFile 上传前做一次校验真正麻烦的是多端 dpr 适配和 canvas 生命周期管理——很多问题不是代码写错了,而是 canvas 被重建了两次,或者导出时机卡在 draw call 还没提交到 GPU。动手前先 console.log 出 dpr、canvas node、ctx 对象,比盲调快得多。