最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3使用Signature Pad實現(xiàn)電子簽名功能

 更新時間:2025年04月11日 11:14:36   作者:zoahxmy0929  
Vue3簽名板是一種在Vue3應用中實現(xiàn)用戶簽名功能的組件,Vue3-signature-pad的實現(xiàn)旨在為開發(fā)者提供一個簡單易用的工具,使用戶能夠在前端界面上進行簽名操作,常見于電子商務、電子合同等場景,本文介紹了Vue3使用Signature Pad實現(xiàn)電子簽名功能,需要的朋友可以參考下

Signature Pad 基礎用法

安裝與引入

首先需要安裝 signature_pad 庫:

npm install signature_pad

然后在Vue組件中引入:

import SignaturePad from "signature_pad";

基本實現(xiàn)

<template>
  <div>
    <div class="signature-pad-container">
      <canvas ref="signaturePad"></canvas>
    </div>
    <button @click="clear">清除</button>
    <button @click="save">保存</button>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import SignaturePad from 'signature_pad'

const signaturePad = ref(null)
let signaturePadInstance = null

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

const clear = () => {
  signaturePadInstance.clear()
}

const save = () => {
  const dataURL = signaturePadInstance.toDataURL()
  console.log(dataURL) // 輸出簽名圖片的Base64編碼
}
</script>

解決簽名位置偏差問題

問題根源分析

簽名位置偏差通常由以下原因?qū)е拢?/p>

  • Canvas尺寸與顯示尺寸不匹配Canvaswidth / height 屬性和CSS的 width / height 樣式,兩者需要一致。
  • 設備像素比(DPR)問題:在高分辨率屏幕上,CSS 像素與設備像素不一致。
  • 坐標系未校正:未考慮設備像素比導致的事件坐標轉(zhuǎn)換錯誤。

解決方案

1. 獲取設備像素比(DPR): 設備像素比(Device Pixel Ratio)表示一個CSS像素對應多少個設備物理像素。

const dpr = window.devicePixelRatio || 1;

2. 正確設置Canvas尺寸: 確保了 Canvas 內(nèi)部繪制緩沖區(qū)的大小與屏幕顯示大小成正確比例。

const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
canvas.style.width = `${rect.width}px`;
canvas.style.height = `${rect.height}px`;

3. 初始化簽名板并調(diào)整筆跡粗細: 根據(jù) DPI 調(diào)整筆跡粗細,確保在高分辨率設備上線條不會顯得過細。

const baseWidth = 2;
signaturePadInstance = new SignaturePad(canvas, {
  minWidth: baseWidth * dpr,
  maxWidth: baseWidth * dpr * 2,
  // 其他配置...
});

4. 坐標系校正:(關(guān)鍵) 使事件坐標與實際繪制位置匹配。

const ctx = canvas.getContext("2d");
ctx.scale(dpr, dpr);

5. 觸摸設備支持: 禁用觸摸設備的默認滾動行為,確保簽名體驗流暢。

canvas.addEventListener("touchstart", preventScroll, { passive: false });
canvas.addEventListener("touchmove", preventScroll, { passive: false });

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

6. 響應式處理: 監(jiān)聽窗口大小變化并重新初始化簽名板,確保在響應式布局中正常工作。

const handleResize = () => {
  if (signaturePadInstance) {
    initSignaturePad(); // 重新初始化以適應新尺寸
  }
};

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

onUnmounted(() => {
  window.removeEventListener("resize", handleResize);
});

代碼

const initSignaturePad = () => {
  nextTick(() => {
    const canvas = signaturePad.value;
    if (canvas) {
      // 1. 獲取設備像素比
      const dpr = window.devicePixelRatio || 1;
      
      // 2. 獲取Canvas的實際顯示尺寸
      const rect = canvas.getBoundingClientRect();
      
      // 3. 設置Canvas的實際繪制尺寸(考慮DPI)
      canvas.width = rect.width * dpr;
      canvas.height = rect.height * dpr;
      
      // 4. 設置Canvas的CSS顯示尺寸(保持與容器一致)
      canvas.style.width = `${rect.width}px`;
      canvas.style.height = `${rect.height}px`;
      
      // 5. 根據(jù)DPI調(diào)整筆跡粗細
      const baseWidth = 2;
      
      // 6. 初始化簽名板
      signaturePadInstance = new SignaturePad(canvas, {
        backgroundColor: "rgb(255, 255, 255)",
        penColor: "rgb(0, 0, 0)",
        minWidth: baseWidth * dpr,
        maxWidth: baseWidth * dpr * 2,
        throttle: 16 // 節(jié)流控制提高性能
      });
      
      // 7. 調(diào)整坐標系以匹配高DPI
      const ctx = canvas.getContext("2d");
      ctx.scale(dpr, dpr);
      
      // 8. 添加觸摸設備支持
      canvas.addEventListener("touchstart", preventScroll, { passive: false });
      canvas.addEventListener("touchmove", preventScroll, { passive: false });
    }
  });
};

效果

完整代碼

<template>
  <div class="signature-container">
    <h2>電子簽名</h2>
    <div class="signature-pad-container">
      <canvas ref="signaturePad" class="signature-pad"></canvas>
    </div>
    <div class="signature-actions">
      <el-button @click="clearSignature">清除</el-button>
      <el-button type="primary" @click="saveSignature">保存簽名</el-button>
    </div>
    <div v-if="signatureUrl" class="signature-preview">
      <el-image v-if="signatureUrl" :src="signatureUrl"></el-image>
    </div>
  </div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, nextTick } from "vue";
import SignaturePad from "signature_pad";

const signaturePad = ref(null);
let signaturePadInstance = null;
const signatureUrl = ref("");

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

    const dpr = window.devicePixelRatio || 1;
    const rect = canvas.getBoundingClientRect();
    
    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
    canvas.style.width = `${rect.width}px`;
    canvas.style.height = `${rect.height}px`;
    
    const baseWidth = 2;
    
    signaturePadInstance = new SignaturePad(canvas, {
      backgroundColor: "rgb(255, 255, 255)",
      penColor: "rgb(0, 0, 0)",
      minWidth: baseWidth * dpr,
      maxWidth: baseWidth * dpr * 2,
      throttle: 16,
      velocityFilterWeight: 0.7,
      minDistance: 5
    });
    
    const ctx = canvas.getContext("2d");
    ctx.scale(dpr, dpr);
    
    // 觸摸支持
    canvas.addEventListener("touchstart", preventScroll, { passive: false });
    canvas.addEventListener("touchmove", preventScroll, { passive: false });
  });
};

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

const clearSignature = () => {
  if (signaturePadInstance) {
    signaturePadInstance.clear();
    signatureUrl.value = "";
  }
};

const saveSignature = () => {
  if (!signaturePadInstance || signaturePadInstance.isEmpty()) {
    ElMessage.warning("請先簽名");
    return;
  }
  
  // 保存高質(zhì)量PNG
  signatureUrl.value = signaturePadInstance.toDataURL('image/png', 1.0);
  ElMessage.success("簽名保存成功");
};

const handleResize = () => {
  if (signaturePadInstance) {
    initSignaturePad();
  }
};

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

onUnmounted(() => {
  window.removeEventListener("resize", handleResize);
});
</script>
<style scoped>
.signature-container {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.signature-pad-container {
  position: relative;
  width: 100%;
  height: 400px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  margin: 20px 0;
}

.signature-pad {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  touch-action: none;
}

.signature-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-bottom: 20px;
}

.signature-preview {
  margin-top: 20px;
  text-align: center;
}
</style>

以上就是Vue3使用Signature Pad實現(xiàn)電子簽名功能的詳細內(nèi)容,更多關(guān)于Vue3 Signature Pad電子簽名的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

永昌县| 平遥县| 铁力市| 民权县| 沅陵县| 遂溪县| 新密市| 米易县| 寿阳县| 盐池县| 宁蒗| 盱眙县| 诏安县| 盐池县| 明光市| 柘荣县| 襄垣县| 祥云县| 元朗区| 谢通门县| 靖边县| 三台县| 寻乌县| 伊宁县| 威远县| 锡林郭勒盟| 哈密市| 永善县| 邵阳市| 岚皋县| 平利县| 昭觉县| 六安市| 奉贤区| 永清县| 大悟县| 涿鹿县| 格尔木市| 阿克苏市| 巴楚县| 贡嘎县|