一、技术选型
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'));