前端如何实现电子签名

1.canvas绘图

通过HTML5的canvas API捕获鼠标或触摸轨迹,实时绘制签名,支持自定义线条样式、颜色和动画效果,生成的签名可以直接转换为图片或矢量数据。但是需要自行处理平滑算法和兼容性问题,移动端触摸事件处理较复杂

html 复制代码
<div class="signature-container">
    <canvas id="signatureCanvas" width="400" height="200"></canvas>
    <div class="signature-actions">
        <button id="clearBtn">清除签名</button>
        <button id="saveBtn">保存签名</button>
    </div>
    <input type="hidden" id="signatureInput" name="signature">
</div>
 
javascript 复制代码
// 获取DOM元素
const canvas = document.getElementById('signatureCanvas');
const ctx = canvas.getContext('2d');
const clearBtn = document.getElementById('clearBtn');
const saveBtn = document.getElementById('saveBtn');
const signatureInput = document.getElementById('signatureInput');

// 初始化画布
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';

// 鼠标/触摸事件变量
let isDrawing = false;
let lastX = 0;
let lastY = 0;

// 开始绘制
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('touchstart', handleTouch);

// 绘制过程
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('touchmove', handleTouchMove);

// 结束绘制
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
canvas.addEventListener('touchend', stopDrawing);

// 清除画布
clearBtn.addEventListener('click', clearCanvas);

// 保存签名
saveBtn.addEventListener('click', saveSignature);

function startDrawing(e) {
    isDrawing = true;
    [lastX, lastY] = [e.offsetX, e.offsetY];
}

function handleTouch(e) {
    e.preventDefault();
    const touch = e.touches[0];
    const mouseEvent = {
        offsetX: touch.clientX - canvas.getBoundingClientRect().left,
        offsetY: touch.clientY - canvas.getBoundingClientRect().top
    };
    startDrawing(mouseEvent);
}

function draw(e) {
    if (!isDrawing) return;
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
    [lastX, lastY] = [e.offsetX, e.offsetY];
}

function handleTouchMove(e) {
    e.preventDefault();
    const touch = e.touches[0];
    const mouseEvent = {
        offsetX: touch.clientX - canvas.getBoundingClientRect().left,
        offsetY: touch.clientY - canvas.getBoundingClientRect().top
    };
    draw(mouseEvent);
}

function stopDrawing() {
    isDrawing = false;
}

function clearCanvas() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    signatureInput.value = '';
}

function saveSignature() {
    const dataURL = canvas.toDataURL('image/png');
    signatureInput.value = dataURL;
    // 可以在这里添加提交表单或AJAX上传的逻辑
}
 
css 复制代码
.signature-container {
    border: 1px solid #ccc;
    padding: 10px;
    margin: 10px 0;
}

#signatureCanvas {
    border: 1px solid #000;
    background-color: #fff;
}

.signature-actions {
    margin-top: 10px;
}

button {
    padding: 5px 10px;
    margin-right: 5px;
}
 

2.SVG路径绘制

使用SVG的<path>元素记录签名轨迹,生成矢量图

优点:生成的签名是矢量图,可无损缩放;支持复杂的动画和交换效果;文件体积小,便于存储和传输;

缺点:路径数据结构较复杂,需手动维护;性能可能低于canvas对于大规模绘制

javascript 复制代码
<svg id="signatureSvg" width="400" height="200" style="border: 1px solid #ccc;"></svg>
<button id="clearSvgBtn">清空</button>

<script>
  const svg = document.getElementById('signatureSvg');
  let currentPath = null;
  let isDrawing = false;

  function startDrawing(e) {
    isDrawing = true;
    const pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    const svgPoint = pt.matrixTransform(svg.getScreenCTM().inverse());
    
    currentPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    currentPath.setAttribute('d', `M ${svgPoint.x} ${svgPoint.y}`);
    currentPath.setAttribute('stroke', '#333');
    currentPath.setAttribute('stroke-width', '2');
    currentPath.setAttribute('fill', 'none');
    currentPath.setAttribute('stroke-linecap', 'round');
    svg.appendChild(currentPath);
  }

  function draw(e) {
    if (!isDrawing || !currentPath) return;
    const pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    const svgPoint = pt.matrixTransform(svg.getScreenCTM().inverse());
    
    const pathData = currentPath.getAttribute('d');
    currentPath.setAttribute('d', `${pathData} L ${svgPoint.x} ${svgPoint.y}`);
  }

  function stopDrawing() {
    isDrawing = false;
    currentPath = null;
  }

  // 绑定事件(与Canvas类似)
  svg.addEventListener('mousedown', startDrawing);
  window.addEventListener('mousemove', draw);
  window.addEventListener('mouseup', stopDrawing);

  document.getElementById('clearSvgBtn').addEventListener('click', () => {
    while (svg.firstChild) {
      svg.removeChild(svg.firstChild);
    }
  });
</script>

3.第三方库(signature pad)

javascript 复制代码
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.5/dist/signature_pad.umd.min.js"></script>
<canvas id="signaturePad" style="border: 1px solid #000;"></canvas>

<script>
  const canvas = document.getElementById('signaturePad');
  const signaturePad = new SignaturePad(canvas);
  
  document.getElementById('clearBtn').addEventListener('click', () => {
    signaturePad.clear();
  });
  
  document.getElementById('saveBtn').addEventListener('click', () => {
    const dataURL = signaturePad.toDataURL();
    // 处理签名数据
  });
</script>

4.表单输入模拟签名

使用文本输入或选择预设签名图片,适用于对签名要求不高的场景

javascript 复制代码
<!-- 文本输入方式 -->
<label>请输入您的签名:</label>
<input type="text" id="signatureText">
<button onclick="generateSignature()">生成签名</button>
<div id="generatedSignature"></div>

<script>
  function generateSignature() {
    const text = document.getElementById('signatureText').value;
    document.getElementById('generatedSignature').innerText = text;
    // 可结合字体样式模拟手写效果
  }
</script>
相关推荐
脑袋大大的1 小时前
JavaScript 性能优化实战:减少 DOM 操作引发的重排与重绘
开发语言·javascript·性能优化
速易达网络2 小时前
RuoYi、Vue CLI 和 uni-app 结合构建跨端全家桶方案
javascript·vue.js·低代码
耶啵奶膘2 小时前
uniapp+firstUI——上传视频组件fui-upload-video
前端·javascript·uni-app
JoJo_Way2 小时前
LeetCode三数之和-js题解
javascript·算法·leetcode
视频砖家3 小时前
移动端Html5播放器按钮变小的问题解决方法
前端·javascript·viewport功能
lyj1689973 小时前
vue-i18n+vscode+vue 多语言使用
前端·vue.js·vscode
小白变怪兽5 小时前
一、react18+项目初始化(vite)
前端·react.js
ai小鬼头5 小时前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
墨菲安全6 小时前
NPM组件 betsson 等窃取主机敏感信息
前端·npm·node.js·软件供应链安全·主机信息窃取·npm组件投毒