网站添加电子签名功能教程

一、技术选型 1. 前端签名库推荐 Signature Pad:轻量级基于Canvas的签名库(本文选用) h

一、技术选型

1. 前端签名库推荐

  • Signature Pad:轻量级基于Canvas的签名库(本文选用)
  • html2canvas:将签名区域转为图片
  • jSignature:支持多种输出格式
  • React-Signature-Canvas(React项目专用)

2. 后端存储方案

  • 签名图片存储(Base64转PNG/JPG)
  • 数据库记录签名元数据(时间戳、用户ID等)
  • 可选PDF集成(用于合同文档)

二、网页版实现代码

1. HTML结构

<div class="signature-container">
  <canvas id="signatureCanvas"></canvas>
  <div class="button-group">
    <button id="clearBtn">清除</button>
    <button id="saveBtn">保存签名</button>
  </div>
  <div id="signatureResult"></div>
</div>

2. JavaScript实现(使用Signature Pad)

// 初始化画布
const canvas = document.getElementById("signatureCanvas");
const signaturePad = new SignaturePad(canvas, {
  backgroundColor: 'rgb(255, 255, 255)',
  penColor: 'rgb(0, 0, 0)'
});

// 响应式调整
function resizeCanvas() {
  const ratio = Math.max(window.devicePixelRatio || 1, 1);
  canvas.width = canvas.offsetWidth * ratio;
  canvas.height = canvas.offsetHeight * ratio;
  canvas.getContext("2d").scale(ratio, ratio);
  signaturePad.clear(); // 清除重绘
}
window.addEventListener("resize", resizeCanvas);
resizeCanvas();

// 清除按钮
document.getElementById("clearBtn").addEventListener("click", () => {
  signaturePad.clear();
});

// 保存按钮
document.getElementById("saveBtn").addEventListener("click", () => {
  if (signaturePad.isEmpty()) {
    alert("请先提供签名");
    return;
  }
  
  const signatureData = signaturePad.toDataURL(); // 获取Base64
  document.getElementById("signatureResult").innerHTML = `<img src="${signatureData}">`;
  
  // 发送到服务器
  fetch('/api/save-signature', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ image: signatureData })
  }).then(response => {
    console.log("签名保存成功(www.02405.com)");
  });
});

三、移动端适配方案

1. 触摸事件优化

// 禁用移动端触摸动作
canvas.style.touchAction = 'none';
canvas.style.msTouchAction = 'none';

// 防止页面滚动
document.body.addEventListener('touchmove', (e) => {
  if (e.target === canvas) {
    e.preventDefault();
  }
}, { passive: false });

2. CSS适配

.signature-container {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
}

#signatureCanvas {
  width: 100%;
  height: 200px;
  border: 1px solid #ccc;
  touch-action: none;
}

.button-group {
  display: flex;
  justify-content: space-between;
  margin-top: 15px;
}

button {
  padding: 10px 20px;
  font-size: 16px;
}

/* 移动端特定样式 */
@media (max-width: 768px) {
  #signatureCanvas {
    height: 150px;
  }
  
  button {
    padding: 8px 15px;
    font-size: 14px;
  }
}

四、后端处理示例(Node.js)

1. 接收并保存签名

const express = require('express');
const fs = require('fs');
const app = express();

app.use(express.json());

app.post('/api/save-signature', (req, res) => {
  const { image } = req.body;
  
  // 移除Base64前缀
  const base64Data = image.replace(/^data:image/png;base64,/, "");
  
  // 生成文件名
  const filename = `signature_${Date.now()}.png`;
  const path = `./signatures/${filename}`;
  
  // 保存文件
  fs.writeFile(path, base64Data, 'base64', (err) => {
    if (err) {
      console.error(err);
      return res.status(500).send("保存失败");
    }
    
    // 这里可以保存到数据库
    // db.saveSignature(filename, userId, etc...)
    
    res.json({ success: true, filename });
  });
});

app.listen(3000, () => console.log('Server running on port 3000'));