签名必须用canvas捕获手写轨迹而非file input:监听touch/mouse事件绘图→todataurl生成base64→存入hidden input提交;注意移动端touch兼容、canvas尺寸设置、线条样式及坐标计算。

签名图片不能直接用 <input type="file"> 上传就完事
浏览器原生 <input type="file"> 只能选本地文件,无法捕获手写轨迹。用户想“签名”,本质是要采集画布上的笔迹,不是挑一张 PNG/JPEG 文件。直接绑 change 事件监听 file input,拿到的只是空值或旧文件——因为签名还没画,根本没生成图片。
必须用 <canvas></canvas> 捕获鼠标/触控轨迹再转成图片
核心路径是:监听 mousedown/touchstart → 记录起点 → mousemove/touchmove 连线 → mouseup/touchend 结束 → 调用 canvas.toDataURL() 生成 base64 图片数据。
- 记得设置
canvas的width和height属性(不是 CSS),否则绘图会拉伸变形 - 移动端必须加
{ passive: false }阻止默认滚动行为,否则touchmove会失效 - 用
ctx.lineCap = 'round'和ctx.lineWidth = 2让线条更自然,避免尖锐折角 - 清空画布别用
canvas.width = canvas.width(重置会丢掉高 DPI 缩放),改用ctx.clearRect(0, 0, canvas.width, canvas.height)
把 base64 图片塞进隐藏 <input type="hidden"> 才能随表单提交
HTML 表单不接受 base64 数据直接提交,必须存到一个不可见但参与序列化的字段里。不能用 <input type="file"> 去“赋值” base64(它只读),得另起一个 <input type="hidden" name="signature">。
- 每次签名完成,执行
hiddenInput.value = canvas.toDataURL('image/png', 0.8)(压缩率 0.8 平衡质量与体积) - 后端收到的是类似
data:image/png;base64,iVBORw0KGgo...的字符串,需按分号分割、解码 base64 再保存为文件 - 如果后端限制字段长度(如 MySQL TEXT),base64 签名可能超限,建议后端转存为二进制 blob 或先上传到对象存储返回 URL
移动端真机调试时 touchstart 经常被忽略
很多安卓浏览器(尤其旧版 WebView)对 touchstart 有 300ms 延迟或拦截,导致第一笔画不出。这不是代码写错,是浏览器策略问题。
- 在
加<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">是基础 - 给 canvas 添加
style="touch-action: none",显式禁用浏览器默认手势 - 监听
touchstart时立刻调用event.preventDefault()(注意:必须在事件 handler 里同步执行) - 别依赖
offsetX/Y(移动端不兼容),改用getBoundingClientRect()计算相对坐标
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











