使用 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在视图中的位置,再通过鼠标位置减去canvas在视图中距离顶部的位置和距离左边的位置就可以得到手指或者鼠标滑动的位置坐标。 然后用lineTo方法设置绘制坐标,再调用stroke方法进行绘制。
鼠标按下调用canvas的beginPath方法开启一个路径。
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>