3 分钟实现一个 Canvas 签名板,支持 PC 和移动端

在很多场景中我们需要用户在线签署,比如:在线合同、快递确认、表单签名等。 今天我们来实现一个简单的 Canvas 签名板 ,它支持 PC 鼠标绘制移动端触摸绘制

需求分析

  1. 实现签名功能。
  2. 既支持鼠标操作,也支持触摸操作。
  3. 支持修改线条宽度和颜色
  4. 支持导出 PNG、SVG、JSON、点坐标等格式

核心思路

  1. 使用 Canvas API 来绘制签名:

    • ctx.beginPath() 开始绘制路径。
    • ctx.moveTo(x, y) 移动画笔到起始点。
    • ctx.lineTo(x, y) 绘制到目标点。
    • ctx.stroke() 执行绘制指令。
  2. 监听鼠标和触摸事件,将用户的手势轨迹映射到 Canvas 上。

  3. 关键点:如何将鼠标/手指在屏幕上的位置,转换为 相对于 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 签名板,就能变成实用的电子签署工具。

相关推荐
阿虎儿4 分钟前
TypeScript 内置工具类型完全指南
前端·javascript·typescript
IT_陈寒12 分钟前
Java性能优化实战:5个立竿见影的技巧让你的应用提速50%
前端·人工智能·后端
chxii43 分钟前
6.3Element UI 的表单
javascript·vue.js·elementui
张努力43 分钟前
从零开始的开发一个vite插件:一个程序员的"意外"之旅 🚀
前端·vue.js
远帆L44 分钟前
前端批量导入内容——word模板方案实现
前端
Codebee1 小时前
OneCode3.0-RAD 可视化设计器 配置手册
前端·低代码
深兰科技1 小时前
深兰科技:搬迁公告,我们搬家了
javascript·人工智能·python·科技·typescript·laravel·深兰科技
葡萄城技术团队1 小时前
【SpreadJS V18.2 新版本】设计器新特性:四大主题方案,助力 UI 个性化与品牌适配
前端
lumi.1 小时前
Swiper属性全解析:快速掌握滑块视图核心配置!(2.3补充细节,详细文档在uniapp官网)
前端·javascript·css·小程序·uni-app