• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

    Vue3使用Signature Pad实现电子签名功能

    发布者: 404号房间 | 发布时间: 2025-6-16 07:39| 查看数: 48| 评论数: 0|帖子模式

    Signature Pad 基础用法


    安装与引入

    首先需要安装
    1. signature_pad
    复制代码
    库:
    1. npm install signature_pad
    复制代码
    然后在Vue组件中引入:
    1. import SignaturePad from "signature_pad";
    复制代码
    基本实现
    1. <template>
    2.   <div>
    3.     <div class="signature-pad-container">
    4.       <canvas ref="signaturePad"></canvas>
    5.     </div>
    6.     <button @click="clear">清除</button>
    7.     <button @click="save">保存</button>
    8.   </div>
    9. </template>

    10. <script setup>
    11. import { ref, onMounted } from 'vue'
    12. import SignaturePad from 'signature_pad'

    13. const signaturePad = ref(null)
    14. let signaturePadInstance = null

    15. onMounted(() => {
    16.   signaturePadInstance = new SignaturePad(signaturePad.value)
    17. })

    18. const clear = () => {
    19.   signaturePadInstance.clear()
    20. }

    21. const save = () => {
    22.   const dataURL = signaturePadInstance.toDataURL()
    23.   console.log(dataURL) // 输出签名图片的Base64编码
    24. }
    25. </script>
    复制代码
    解决签名位置偏差问题


    问题根源分析

    签名位置偏差通常由以下原因导致:

    • Canvas尺寸与显示尺寸不匹配
      1. Canvas
      复制代码
      1. width
      复制代码
      /
      1. height
      复制代码
      属性和CSS的
      1. width
      复制代码
      /
      1. height
      复制代码
      样式,两者需要一致。
    • 设备像素比(DPR)问题:在高分辨率屏幕上,
      1. CSS
      复制代码
      像素与设备像素不一致。
    • 坐标系未校正:未考虑设备像素比导致的事件坐标转换错误。

    解决方案

    1. 获取设备像素比(DPR): 设备像素比(Device Pixel Ratio)表示一个CSS像素对应多少个设备物理像素。
    1. const dpr = window.devicePixelRatio || 1;
    复制代码
    2. 正确设置Canvas尺寸: 确保了 Canvas 内部绘制缓冲区的大小与屏幕显示大小成正确比例。
    1. const rect = canvas.getBoundingClientRect();
    2. canvas.width = rect.width * dpr;
    3. canvas.height = rect.height * dpr;
    4. canvas.style.width = `${rect.width}px`;
    5. canvas.style.height = `${rect.height}px`;
    复制代码
    3. 初始化签名板并调整笔迹粗细: 根据 DPI 调整笔迹粗细,确保在高分辨率设备上线条不会显得过细。
    1. const baseWidth = 2;
    2. signaturePadInstance = new SignaturePad(canvas, {
    3.   minWidth: baseWidth * dpr,
    4.   maxWidth: baseWidth * dpr * 2,
    5.   // 其他配置...
    6. });
    复制代码
    4. 坐标系校正:(关键) 使事件坐标与实际绘制位置匹配。
    1. const ctx = canvas.getContext("2d");
    2. ctx.scale(dpr, dpr);
    复制代码
    5. 触摸设备支持: 禁用触摸设备的默认滚动行为,确保签名体验流畅。
    1. canvas.addEventListener("touchstart", preventScroll, { passive: false });
    2. canvas.addEventListener("touchmove", preventScroll, { passive: false });

    3. const preventScroll = (e) => {
    4.   e.preventDefault();
    5. };
    复制代码
    6. 响应式处理: 监听窗口大小变化并重新初始化签名板,确保在响应式布局中正常工作。
    1. const handleResize = () => {
    2.   if (signaturePadInstance) {
    3.     initSignaturePad(); // 重新初始化以适应新尺寸
    4.   }
    5. };

    6. onMounted(() => {
    7.   window.addEventListener("resize", handleResize);
    8. });

    9. onUnmounted(() => {
    10.   window.removeEventListener("resize", handleResize);
    11. });
    复制代码
    代码
    1. const initSignaturePad = () => {
    2.   nextTick(() => {
    3.     const canvas = signaturePad.value;
    4.     if (canvas) {
    5.       // 1. 获取设备像素比
    6.       const dpr = window.devicePixelRatio || 1;
    7.       
    8.       // 2. 获取Canvas的实际显示尺寸
    9.       const rect = canvas.getBoundingClientRect();
    10.       
    11.       // 3. 设置Canvas的实际绘制尺寸(考虑DPI)
    12.       canvas.width = rect.width * dpr;
    13.       canvas.height = rect.height * dpr;
    14.       
    15.       // 4. 设置Canvas的CSS显示尺寸(保持与容器一致)
    16.       canvas.style.width = `${rect.width}px`;
    17.       canvas.style.height = `${rect.height}px`;
    18.       
    19.       // 5. 根据DPI调整笔迹粗细
    20.       const baseWidth = 2;
    21.       
    22.       // 6. 初始化签名板
    23.       signaturePadInstance = new SignaturePad(canvas, {
    24.         backgroundColor: "rgb(255, 255, 255)",
    25.         penColor: "rgb(0, 0, 0)",
    26.         minWidth: baseWidth * dpr,
    27.         maxWidth: baseWidth * dpr * 2,
    28.         throttle: 16 // 节流控制提高性能
    29.       });
    30.       
    31.       // 7. 调整坐标系以匹配高DPI
    32.       const ctx = canvas.getContext("2d");
    33.       ctx.scale(dpr, dpr);
    34.       
    35.       // 8. 添加触摸设备支持
    36.       canvas.addEventListener("touchstart", preventScroll, { passive: false });
    37.       canvas.addEventListener("touchmove", preventScroll, { passive: false });
    38.     }
    39.   });
    40. };
    复制代码
    效果



    完整代码
    1. <template>
    2.   <div class="signature-container">
    3.     <h2>电子签名</h2>
    4.     <div class="signature-pad-container">
    5.       <canvas ref="signaturePad" class="signature-pad"></canvas>
    6.     </div>
    7.     <div class="signature-actions">
    8.       <el-button @click="clearSignature">清除</el-button>
    9.       <el-button type="primary" @click="saveSignature">保存签名</el-button>
    10.     </div>
    11.     <div v-if="signatureUrl" class="signature-preview">
    12.       <el-image v-if="signatureUrl" :src="signatureUrl"></el-image>
    13.     </div>
    14.   </div>
    15. </template>
    复制代码
    1. <script setup>
    2. import { ref, onMounted, onUnmounted, nextTick } from "vue";
    3. import SignaturePad from "signature_pad";

    4. const signaturePad = ref(null);
    5. let signaturePadInstance = null;
    6. const signatureUrl = ref("");

    7. const initSignaturePad = () => {
    8.   nextTick(() => {
    9.     const canvas = signaturePad.value;
    10.     if (!canvas) return;

    11.     const dpr = window.devicePixelRatio || 1;
    12.     const rect = canvas.getBoundingClientRect();
    13.    
    14.     canvas.width = rect.width * dpr;
    15.     canvas.height = rect.height * dpr;
    16.     canvas.style.width = `${rect.width}px`;
    17.     canvas.style.height = `${rect.height}px`;
    18.    
    19.     const baseWidth = 2;
    20.    
    21.     signaturePadInstance = new SignaturePad(canvas, {
    22.       backgroundColor: "rgb(255, 255, 255)",
    23.       penColor: "rgb(0, 0, 0)",
    24.       minWidth: baseWidth * dpr,
    25.       maxWidth: baseWidth * dpr * 2,
    26.       throttle: 16,
    27.       velocityFilterWeight: 0.7,
    28.       minDistance: 5
    29.     });
    30.    
    31.     const ctx = canvas.getContext("2d");
    32.     ctx.scale(dpr, dpr);
    33.    
    34.     // 触摸支持
    35.     canvas.addEventListener("touchstart", preventScroll, { passive: false });
    36.     canvas.addEventListener("touchmove", preventScroll, { passive: false });
    37.   });
    38. };

    39. const preventScroll = (e) => {
    40.   e.preventDefault();
    41. };

    42. const clearSignature = () => {
    43.   if (signaturePadInstance) {
    44.     signaturePadInstance.clear();
    45.     signatureUrl.value = "";
    46.   }
    47. };

    48. const saveSignature = () => {
    49.   if (!signaturePadInstance || signaturePadInstance.isEmpty()) {
    50.     ElMessage.warning("请先签名");
    51.     return;
    52.   }
    53.   
    54.   // 保存高质量PNG
    55.   signatureUrl.value = signaturePadInstance.toDataURL('image/png', 1.0);
    56.   ElMessage.success("签名保存成功");
    57. };

    58. const handleResize = () => {
    59.   if (signaturePadInstance) {
    60.     initSignaturePad();
    61.   }
    62. };

    63. onMounted(() => {
    64.   initSignaturePad();
    65.   window.addEventListener("resize", handleResize);
    66. });

    67. onUnmounted(() => {
    68.   window.removeEventListener("resize", handleResize);
    69. });
    70. </script>
    复制代码
    1. <style scoped>
    2. .signature-container {
    3.   max-width: 800px;
    4.   margin: 0 auto;
    5.   padding: 20px;
    6. }

    7. .signature-pad-container {
    8.   position: relative;
    9.   width: 100%;
    10.   height: 400px;
    11.   border: 1px solid #dcdfe6;
    12.   border-radius: 4px;
    13.   margin: 20px 0;
    14. }

    15. .signature-pad {
    16.   position: absolute;
    17.   top: 0;
    18.   left: 0;
    19.   width: 100%;
    20.   height: 100%;
    21.   touch-action: none;
    22. }

    23. .signature-actions {
    24.   display: flex;
    25.   justify-content: flex-end;
    26.   gap: 10px;
    27.   margin-bottom: 20px;
    28. }

    29. .signature-preview {
    30.   margin-top: 20px;
    31.   text-align: center;
    32. }
    33. </style>
    复制代码
    以上就是Vue3使用Signature Pad实现电子签名功能的详细内容,更多关于Vue3 Signature Pad电子签名的资料请关注脚本之家其它相关文章!

    来源:https://www.jb51.net/javascript/339460qw4.htm
    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    ×

    最新评论

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表