Vue實(shí)現(xiàn)電子簽名功能的完整代碼
一、具體思路
在vue項(xiàng)目中使用以下步驟思路去實(shí)現(xiàn):
起初的原始文檔的格式都轉(zhuǎn)成圖片格式來(lái)處理;
電子簽名的模板轉(zhuǎn)成base64
前端將文檔的樣式和電子簽名的模板合成一張圖片,進(jìn)行預(yù)覽
通過(guò)原始圖片文檔與電子簽名的圖片進(jìn)行合并,期間需要調(diào)整簽名base64的位置和縮放比例,然后添加合并到原始文檔,最終形成簽名后的文檔。
二、所需依賴
npm i signature_pad@4.2.0 npm i html2canvas
signature_pad 簽名板
signature_pad - npm
html2canvas html轉(zhuǎn)cavas
html2canvas - npm
三、添加簽名面板
<div class="sign-box" style="width:300px;height:200px;padding: 10px; margin:10px;background-color: rgb(221 216 216);"> <p><span style="color: #f00;">*</span>簽名版<span style="color: #f00;">*</span></p> <div> <canvas id="signCanvas"/> </div> <button type="default" @click="clear()">清除</button> <button type="default" @click="review()">游覽</button> <button aria-placeholder="添加簽名到文件" type="default" @click="submit()">提交</button> </div>
import SignaturePad from 'signature_pad'
mounted() { const canvas = document.getElementById('signCanvas') this.signatureExample = new SignaturePad(canvas, { penColor: 'rgb(0, 0, 0)' }) //penColor 筆的顏色 },
發(fā)現(xiàn)我鼠標(biāo)所在的位置跟落筆產(chǎn)生了偏移 需要調(diào)用一下這個(gè) adjustSignatureImgPos這個(gè)方法
//校正簽名位置偏移 adjustSignatureImgPos() { const canvas = document.getElementById('signCanvas') const ratio = Math.max(window.devicePixelRatio || 1, 1) // 清除畫布 canvas.width = canvas.offsetWidth * ratio canvas.height = canvas.offsetHeight * ratio canvas.getContext('2d').scale(ratio, ratio) },
mounted() { const canvas = document.getElementById('signCanvas') this.signatureExample = new SignaturePad(canvas, { penColor: 'rgb(0, 0, 0)' }) //penColor 筆的顏色 this.adjustSignatureImgPos() },
3.1 canvas 轉(zhuǎn)base64
this.signatureimgSrc =this.signatureExample.toDataURL('image/png') //得到了就是base64的
打印輸入如下:
3.2 電子簽名等比例縮小
把生成的電子簽名等比例縮小
傳入我們電子簽名的base64,然后生成一個(gè)新元素image ,改變它的大小,然后在通過(guò)canvas轉(zhuǎn)成base64,在return 出來(lái)
我們需要使用Promise去異步處理他,并拿到返回的新base64
// 繪制的canvas 進(jìn)行縮放并轉(zhuǎn)為base64 resizeImage(src) { return new Promise((resolve) => { const img = new Image() img.src = src img.onload = () => { const originalWidth = img.width const originalHeight = img.height const scaleFactor = 0.5 // 縮放的倍數(shù) const resizedWidth = originalWidth * scaleFactor const resizedHeight = originalHeight * scaleFactor const canvas = document.createElement('canvas') canvas.width = resizedWidth canvas.height = resizedHeight const ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0, resizedWidth, resizedHeight) const base64 = canvas.toDataURL('image/png') resolve(base64) } }) },
效果如下:
四、html轉(zhuǎn)cavas(原始文檔)
我們需要把html編寫的文檔轉(zhuǎn)成base64
這個(gè)我們用html2canvas 這個(gè)插件:
import html2canvas from 'html2canvas'
html2canvas(document.querySelector("#capture")).then(canvas => { this.htmlimgUrl = canvas.toDataURL("image/png"); // 將canvas轉(zhuǎn)換成img的src流 });
五、合成圖片
接下來(lái)我們需要將html文檔和電子簽名模板,合成一張圖片
寫一個(gè)合并圖片的方法:
傳入兩個(gè)參數(shù),分別是原始圖片文檔和電子簽名圖片文檔;
//合并圖片 mergeimg(imgUrl,signatureimgSrc){ // 創(chuàng)建一個(gè) canvas 元素 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // 創(chuàng)建兩個(gè)圖像對(duì)象 const img1 = new Image(); const img2 = new Image(); // 設(shè)置圖像的 src 屬性為 Base64 編碼的字符串 img1.src = imgUrl; img2.src = signatureimgSrc; // 設(shè)置 canvas 的寬度和高度 // 這里假設(shè)我們將圖像水平排列,因此寬度是兩幅圖寬度之和,高度取最大值 canvas.width = img1.width + img2.width; canvas.height = Math.max(img1.height, img2.height); // 繪制第一張圖像 ctx.drawImage(img1, 0, 0); // 繪制第二張圖像,放置在第一張圖像的右邊 ctx.drawImage(img2, 300, 500); // 將合并后的圖像導(dǎo)出為 Base64 編碼的字符串 this.mergedImage = canvas.toDataURL('image/png'); },
調(diào)用合并圖片方法:
//點(diǎn)擊提交 進(jìn)行合并圖片 保存簽名面板內(nèi)容 submit(){ this.mergeimg(this.imgUrl,this.signatureimgSrcScale) },
六、效果測(cè)試
七、完整源碼
<template> <div class="page"> <div> <h3>原文檔</h3> <h3>-----------------------</h3> <img :src="imgUrl"> </div> <div class="sign-box" style="width:300px;height:200px;padding: 10px; margin:10px;background-color: rgb(221 216 216);"> <p><span style="color: #f00;">*</span>簽名版<span style="color: #f00;">*</span></p> <div> <canvas id="signCanvas"/> </div> <button type="default" @click="clear()">清除</button> <button type="default" @click="review()">游覽</button> <button aria-placeholder="添加簽名到文件" type="default" @click="submit()">提交</button> </div> <div> <h3>簽名</h3> <img :src="signatureimgSrcScale"> </div> <div> <h3>簽名后的文檔</h3> <h3>-----------------------</h3> <img :src="mergedImage"> </div> </div> </template> <script> import SignaturePad from 'signature_pad' import html2canvas from 'html2canvas' import pdf from 'vue-pdf' export default { components: { pdf }, data() { return { imgUrl: '../../static/file.png', signatureimgSrc: null, htmlimgUrl: null, signatureExample: null, mergedImage: null, signatureimgSrcScale: null } }, mounted() { const canvas = document.getElementById('signCanvas') this.signatureExample = new SignaturePad(canvas, { penColor: 'rgb(0, 0, 0)' }) //penColor 筆的顏色 this.adjustSignatureImgPos() }, created() { }, methods: { //校正簽名位置偏移 adjustSignatureImgPos() { const canvas = document.getElementById('signCanvas') const ratio = Math.max(window.devicePixelRatio || 1, 1) // 清除畫布 canvas.width = canvas.offsetWidth * ratio canvas.height = canvas.offsetHeight * ratio canvas.getContext('2d').scale(ratio, ratio) }, //html頁(yè)面內(nèi)容轉(zhuǎn)為base64 html2base64(){ html2canvas(document.querySelector("#capture")).then(canvas => { this.htmlimgUrl = canvas.toDataURL("image/png"); // 將canvas轉(zhuǎn)換成img的src流 }); }, //合并圖片 mergeimg(imgUrl,signatureimgSrc){ // 創(chuàng)建一個(gè) canvas 元素 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // 創(chuàng)建兩個(gè)圖像對(duì)象 const img1 = new Image(); const img2 = new Image(); // 設(shè)置圖像的 src 屬性為 Base64 編碼的字符串 img1.src = imgUrl; img2.src = signatureimgSrc; // 等待兩張圖像都加載完畢 // await Promise.all([this.loadImage(img1), this.loadImage(img2)]); // 設(shè)置 canvas 的寬度和高度 // 這里假設(shè)我們將圖像水平排列,因此寬度是兩幅圖寬度之和,高度取最大值 canvas.width = img1.width + img2.width; canvas.height = Math.max(img1.height, img2.height); // 繪制第一張圖像 ctx.drawImage(img1, 0, 0); // 繪制第二張圖像,放置在第一張圖像的右邊 ctx.drawImage(img2, 300, 500); // 將合并后的圖像導(dǎo)出為 Base64 編碼的字符串 this.mergedImage = canvas.toDataURL('image/png'); }, loadImage(img) { return new Promise((resolve, reject) => { img.onload = resolve; img.onerror = reject; }); }, //點(diǎn)擊清除按鈕 清除簽名面板內(nèi)容 clear(){ //清除簽名面板的方法 this.signatureExample.clear() }, async review(){ this.signatureimgSrc =this.signatureExample.toDataURL('image/png') this.signatureimgSrcScale =await this.resizeImage(this.signatureExample.toDataURL('image/png')) console.log("======== this.signatureimgSrc==========", this.signatureimgSrc) }, //點(diǎn)擊提交 進(jìn)行合并圖片 保存簽名面板內(nèi)容 submit(){ this.mergeimg(this.imgUrl,this.signatureimgSrcScale) }, // 繪制的canvas 進(jìn)行縮放并轉(zhuǎn)為base64 resizeImage(src) { return new Promise((resolve) => { const img = new Image() img.src = src img.onload = () => { const originalWidth = img.width const originalHeight = img.height const scaleFactor = 0.5 // 縮放的倍數(shù) const resizedWidth = originalWidth * scaleFactor const resizedHeight = originalHeight * scaleFactor const canvas = document.createElement('canvas') canvas.width = resizedWidth canvas.height = resizedHeight const ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0, resizedWidth, resizedHeight) const base64 = canvas.toDataURL('image/png') resolve(base64) } }) }, } } </script> <style> .page{ display: flex; flex-direction: row; margin: 10px; text-align: center; background: #fff; padding: 10px; } </style>
到此這篇關(guān)于Vue實(shí)現(xiàn)電子簽名功能的完整代碼的文章就介紹到這了,更多相關(guān)Vue電子簽名內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3在Setup中使用axios請(qǐng)求獲取的值方式
這篇文章主要介紹了Vue3在Setup中使用axios請(qǐng)求獲取的值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06vue-router項(xiàng)目實(shí)戰(zhàn)總結(jié)篇
vue-router 是 Vue.js 官方的路由庫(kù).這篇文章主要介紹了vue-router項(xiàng)目實(shí)戰(zhàn)總結(jié),需要的朋友可以參考下2018-02-02Vue.js中實(shí)現(xiàn)密碼修改及頁(yè)面跳轉(zhuǎn)和刷新的完整指南
在現(xiàn)代Web應(yīng)用中,用戶賬戶管理是一個(gè)核心功能,其中密碼修改是一個(gè)常見(jiàn)的需求,本文將詳細(xì)介紹如何在Vue.js應(yīng)用中實(shí)現(xiàn)用戶密碼修改功能,并在成功后跳轉(zhuǎn)到登錄頁(yè)面并刷新該頁(yè)面,需要的朋友可以參考下2024-12-12解決vue scoped html樣式無(wú)效的問(wèn)題
這篇文章主要介紹了解決vue scoped html樣式無(wú)效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10Vue中實(shí)現(xiàn)父子組件雙向數(shù)據(jù)流的三種方案分享
通常情況下,父子組件的通信都是單向的,或父組件使用props向子組件傳遞數(shù)據(jù),或子組件使用emit函數(shù)向父組件傳遞數(shù)據(jù),本文將嘗試講解Vue中常用的幾種雙向數(shù)據(jù)流的使用,需要的朋友可以參考下2023-08-08vue 數(shù)據(jù)操作相關(guān)總結(jié)
這篇文章主要介紹了vue 數(shù)據(jù)操作的相關(guān)資料,幫助大家更好的理解和使用vue,感興趣的朋友可以了解下2020-12-12Vue-drag-resize 拖拽縮放插件的使用(簡(jiǎn)單示例)
本文通過(guò)代碼給大家介紹了Vue-drag-resize 拖拽縮放插件使用簡(jiǎn)單示例,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12