在很多场景中我们需要用户在线签署,比如:在线合同、快递确认、表单签名等。 今天我们来实现一个简单的 Canvas 签名板 ,它支持 PC 鼠标绘制 和 移动端触摸绘制。
需求分析
- 实现签名功能。
- 既支持鼠标操作,也支持触摸操作。
- 支持修改线条宽度和颜色
- 支持导出 PNG、SVG、JSON、点坐标等格式
核心思路
-
使用 Canvas API 来绘制签名:
ctx.beginPath()
开始绘制路径。ctx.moveTo(x, y)
移动画笔到起始点。ctx.lineTo(x, y)
绘制到目标点。ctx.stroke()
执行绘制指令。
-
监听鼠标和触摸事件,将用户的手势轨迹映射到 Canvas 上。
-
关键点:如何将鼠标/手指在屏幕上的位置,转换为 相对于 Canvas 的坐标。
- 使用
element.getBoundingClientRect()
获取 Canvas 的偏移量。
- 使用
整体思维导图

实现步骤
1. 封装获取坐标值的工具类(兼容鼠标和触摸事件)
js
function getCoordinates(e) {
let x, y;
if (e.type.includes('touch')) {
const touch = e.touches[0] || e.changedTouches[0];
const rect = canvas.getBoundingClientRect();
x = touch.clientX - rect.left;
y = touch.clientY - rect.top;
} else {
const rect = canvas.getBoundingClientRect();
x = e.clientX - rect.left;
y = e.clientY - rect.top;
}
return [x, y];
}
2. 创建 Canvas
html
<canvas id="signatureCanvas"></canvas>
3. 监听鼠标事件
js
// 鼠标按下
canvas.addEventListener('mousedown', startDrawing); // 开始绘制
// 鼠标移动
canvas.addEventListener('mousemove', draw); // 绘制线条
// 鼠标弹起
canvas.addEventListener('mouseup', stopDrawing); // 结束绘制
// 鼠标从元素上移出,防止用户将鼠标移出画布时意外中断绘制状态
canvas.addEventListener('mouseout', stopDrawing); // 结束绘制
4. 监听触摸事件(移动端)
js
canvas.addEventListener('touchstart', startDrawing); // 开始绘制
canvas.addEventListener('touchmove', draw); // 绘制线条
canvas.addEventListener('touchend', stopDrawing); // 结束绘制
5. 开始绘制 startDrawing 具体实现
js
function startDrawing(e) {
isDrawing = true;
[lastX, lastY] = getCoordinates(e);
// 开始新路径
currentPath = {
points: [], // 点坐标列表
color: strokeStyle, // 线条颜色
width: lineWidth // 线条宽度
};
}
6. 绘制中 draw 具体实现
js
function draw(e) {
if (!isDrawing) return;
const [x, y] = getCoordinates(e);
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.strokeStyle = strokeStyle;
ctx.lineWidth = lineWidth; // 设置的线条宽度
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.stroke();
// 记录点
if (currentPath) {
currentPath.points.push({x, y});
}
[lastX, lastY] = [x, y];
}
7.结束绘制 stopDrawing 具体实现
js
function stopDrawing() {
if (!isDrawing) return;
isDrawing = false;
// 保存当前路径,便于后续撤销、重绘、导出等操作
if (currentPath && currentPath.points.length > 0) {
drawingData.push(currentPath);
}
currentPath = null;
}
8. 设置线条宽度
js
function setWidth() {
lineWidth = lineWidth < 10 ? lineWidth + 1 : 1;
widthValue.textContent = lineWidth;
}
导出图片等功能
js
function exportPNG() {
const dataURL = canvas.toDataURL('image/png');
console.log("PNG Base64:", dataURL);
return dataURL;
}
总结
通过简单的 Canvas API + 鼠标/触摸事件 ,我们就能实现一个跨平台的签名功能。 这类功能的关键在于 事件处理 和 坐标转换,同时也为我们理解前端与用户交互提供了一个很好案例。
当然,实际项目中我们还可以做更多扩展,比如:
- 增加 清空画布、撤销操作;
- 支持 保存为图片并上传服务器;
- 提供 不同颜色和笔刷粗细选择。
这样,一个小小的 Canvas 签名板,就能变成实用的电子签署工具。