使用 HTML5 Canvas 实现签名功能
在现代网页应用中,电子签名越来越常见,尤其是在合同签署和表单提交中。使用 HTML5 的 <canvas>
元素,我们可以轻松地创建一个签名捕捉工具。本文将带你一步步实现一个简单的签名应用程序。
1. 项目准备
创建基本 HTML 结构:首先,我们需要设置 HTML 页面。我们将包含一个画布元素用于绘制签名,以及一个按钮用于保存签名。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .wrap { margin: 50px; width: 500px; } canvas { border: 1px solid #000; } .save-btn { width: 200px; height: 30px; line-height: 30px; font-size: 16px; color: #999; cursor: pointer; border: 1px solid; text-align: center; margin: 0 auto; } </style> </head> <body> <div class="wrap"> <canvas id="canvas"></canvas> <div class="save-btn">保存</div> </div> </body> </html>
2. JavaScript 实现签名功能
接下来,我们需要添加 JavaScript 代码,以便处理用户的绘图操作并保存签名。
初始化 Canvas
首先,我们获取画布元素并设置其大小和绘图上下文:
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500; // 设定画布宽度
canvas.height = 300; // 设定画布高度
let isDrawing = false;
处理绘图事件
我们将添加事件监听器,以便用户能够使用鼠标或触摸在画布上绘制签名。这个功能主要用到三个事件,鼠标按下,鼠标移动,鼠标离开。鼠标按下允许移动调用beginPath方法。在鼠标移动事件中,先用getBoundingClientRect对象获取canvas在视图中的位置,计算相对坐标。 lineTo方法设置绘制坐标,再调用stroke方法进行绘制。
按下开启一个路径
const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); const saveBtn = document.querySelector('.save-btn'); canvas.width = 500; canvas.height = 300; let isDrawing = false; canvas.addEventListener('mousedown', (e) => { isDrawing = true; ctx.beginPath(); }) canvas.addEventListener('mousemove', (e) => { if (isDrawing) { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = 'red'; ctx.lineTo(x, y); ctx.stroke() } }) canvas.addEventListener('mouseup', () => { isDrawing = false; })
添加移动端支持
canvas.addEventListener('touchstart', (e) => { isDrawing = true; ctx.beginPath(); e.preventDefault(); // 防止触摸移动时页面滚动 }); canvas.addEventListener('touchmove', (e) => { if (isDrawing) { const rect = canvas.getBoundingClientRect(); const x = e.touches[0].clientX - rect.left; const y = e.touches[0].clientY - rect.top; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = 'red'; ctx.lineTo(x, y); ctx.stroke(); } }); canvas.addEventListener('touchend', () => { isDrawing = false; });
保存签名功能
最后,我们需要实现保存签名的功能。我们将使用 toBlob
方法将画布内容转换为图片。
const saveBtn = document.querySelector('#saveBtn'); saveBtn.addEventListener('click', () => { saveSignature(); }); function saveSignature() { canvas.toBlob((blob) => { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'signature.png'; // 指定下载文件的名称 a.click(); }, 'image/png'); }
3. 完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .wrap { margin: 50px; width: 500px; } canvas { border: 1px solid #000; } .save-btn { width: 200px; height: 30px; line-height: 30px; font-size: 16px; color: #999; cursor: pointer; border: 1px solid; text-align: center; margin: 0 auto; } </style> </head> <body> <div class="wrap"> <canvas id="canvas"></canvas> <div class="save-btn">保存</div> </div> <script> const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); const saveBtn = document.querySelector('.save-btn'); canvas.width = 500; canvas.height = 300; let isDrawing = false; // 开始绘图 canvas.addEventListener('mousedown', (e) => { isDrawing = true; ctx.beginPath(); }) // 绘制 canvas.addEventListener('mousemove', (e) => { if (isDrawing) { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = 'red'; ctx.lineTo(x, y); ctx.stroke() } }) // 停止绘图 canvas.addEventListener('mouseup', () => { isDrawing = false; }) // 开始绘图 canvas.addEventListener('touchstart', (e) => { isDrawing = true; ctx.beginPath(); }) // 绘制 canvas.addEventListener('touchmove', (e) => { if (isDrawing) { const rect = canvas.getBoundingClientRect(); const x = e.touches[0].clientX - rect.left; const y = e.touches[0].clientY - rect.top; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = 'red'; ctx.lineTo(x, y); ctx.stroke() } }) // 停止绘图 canvas.addEventListener('touchend', () => { isDrawing = false; }) saveBtn.addEventListener('click', () => { save() }) function save() { // 将画布内容转换为图片 canvas.toBlob(function (blob) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'canvas_image.png'; // 指定下载文件的名称 a.click() }, 'image/png'); } </script> </body> </html>