vue3.0實(shí)現(xiàn)移動(dòng)端電子簽名組件
本文實(shí)例為大家分享了vue3.0實(shí)現(xiàn)移動(dòng)端電子簽名組件的具體代碼,供大家參考,具體內(nèi)容如下
因業(yè)務(wù)需求,前段時(shí)間寫了一個(gè)電子簽名組件,在這里記錄一下,繪圖需求,首先肯定需要使用
canvas標(biāo)簽,考慮到在移動(dòng)端使用,所以選擇使用touch事件。
首先奉上html結(jié)構(gòu)(該組件為橫屏展示):
<div class="signName" :style="{top:0,left:differ+'px'}"> ? ? <div class="close" @click="close"><img src="../assets/images/close.png" alt=""></div> ? ?<div class="autographBox"> ? ? ? <div ref="canvasHW"> ? ? ? ?<canvas ? ? ? ? @touchstart="touchStart($event)" ? ? ? ? @touchmove="touchMove($event)" ? ? ? ? @touchend="touchEnd($event)" ? ? ? ? ref="canvasF" ? ? ? ></canvas> ? ? ? </div> ? ? ? <p v-if="!isDraw">請本人簽名</p> ? ?</div> ? ? <div class="autographBtn"> ? ? ? <div @click="overwrite">重簽</div> ? ? ? <div @click="seaveImages">確定</div> ? ? </div> </div>
css樣式:
.signName{ ? position: fixed; ? height: 100vw; ? width: 100vh; ? background-color: #fff; ? transform:rotate(90deg); ? -webkit-transform:rotate(90deg); ? transform-origin: left top; ? z-index: 1000; ? /* top:0; ? left: 0; */ } .close{ ? width: 100%; ? height: 10%; ? padding-left: 2.5rem; ? padding-top: 1.2rem; } .close img{ ? width: 2rem; } ?.autographBox{ ? width: 100%; ? height: 80%; ? position: relative; }? .autographBox div{ ? width: 100%; ? height: 100%; } .autographBox canvas{ ? width: 100%; ? height: 100%; } .signName p{ ? position: absolute; ? top:50%; ? left: 50%; ? transform: translate(-50%,-50%); ? font-size: 4rem; ? font-weight: bolder; ? color:#436CDF; ? opacity: 0.1; }? .autographBtn{ ? width: 100%; ? height: 10%; ? display: flex; ? justify-content: center; ? align-items: center; } .autographBtn div{ ? width: 50%; ? height: 100%; ? color: #fff; ? display: flex; ? justify-content: center; ? align-items: center; ? font-size: 1.3rem; } .autographBtn div:first-child{ ? opacity: 0.4; ? background: ?-webkit-linear-gradient(top, #728CFD 0%,#5C7EFE 100%); } .autographBtn div:last-child{ ? background: ?-webkit-linear-gradient(top, #728CFD 0%,#5C7EFE 100%); }
其次定義變量,初始化canvas:
var differ = ref(document.documentElement.clientWidth) var canvasF = ref(null); var canvasHW = ref(null); var canvasTxt = null; //畫布 var points = []; // 記錄點(diǎn) var isDraw = ref(false); //簽名標(biāo)記 var startX = 0; //開始坐標(biāo)x var startY = 0;//開始坐標(biāo)y var moveY= 0; var moveX= 0; var strDataURI ='' // 保存的canvas圖像 ? ? onMounted(() =>{ ? ? ? let canvas =canvasF.value; ? ? ? canvas.height = canvasHW.value.offsetHeight - 10; ? ? ? canvas.width = canvasHW.value.offsetWidth - 10; ? ? ? canvasTxt = canvas.getContext("2d"); ? ? ? canvasTxt.strokeStyle = '#333'; ? ? ? canvasTxt.lineWidth = '3'; ? ? })?
主要事件方法如下:
1、touchstart
const touchStart = (ev) => { ? ? ? ev = ev || event; ? ? ? ev.preventDefault(); ? ? ? if (ev.touches.length == 1) { ? ? ? ? isDraw.value = true; //簽名標(biāo)記 ? ? ? ? let obj = { ? ? ? ? ? x: ev.targetTouches[0].clientY, ? ? ? ? ? y: differ.value- ev.targetTouches[0].clientX - (differ.value*0.1) ? ? ? ? }; //y的計(jì)算值中:document.body.offsetHeight*0.5代表的是除了整個(gè)畫板signatureBox剩余的高,this.$refs.canvasHW.offsetHeight*0.1是畫板中標(biāo)題的高 ? ? ? ? startX = obj.x; ? ? ? ? startY = obj.y; ? ? ? ? canvasTxt.beginPath();//開始作畫 ? ? ? ? points.push(obj);//記錄點(diǎn) ? ? ? } ? ? }
2、touchmove
const touchMove = (ev)=> { ? ? ? ev = ev || event; ? ? ? ev.preventDefault(); ? ? ? if (ev.touches.length == 1) { ? ? ? ? let obj = { ? ? ? ? ? x: ev.targetTouches[0].clientY, ? ? ? ? ? y: differ.value- ev.targetTouches[0].clientX - (differ.value*0.1) ? ? ? ? }; ? ? ? ? moveY = obj.y; ? ? ? ? moveX = obj.x; ? ? ? ? canvasTxt.moveTo(startX, startY);//移動(dòng)畫筆 ? ? ? ? canvasTxt.lineTo(obj.x, obj.y);//創(chuàng)建線條 ? ? ? ? canvasTxt.stroke();//畫線 ? ? ? ? startY = obj.y; ? ? ? ? startX = obj.x; ? ? ? ? points.push(obj);//記錄點(diǎn) ? ? ? } ? ? }
3、touchend
const touchEnd = (ev)=> { ? ? ? ev = ev || event; ? ? ? ev.preventDefault(); ? ? ? if (ev.touches.length == 1) { ? ? ? ? let obj = { ? ? ? ? ? x: ev.targetTouches[0].clientY, ? ? ? ? ? y: differ.value- ev.targetTouches[0].clientX - (differ.value*0.1) ? ? ? ? }; ? ? ? ? points.push(obj);//記錄點(diǎn) ? ? ? ? points.push({ x: -1, y: -1 });//記錄點(diǎn) ? ? ? ? canvasTxt.closePath();//收筆 ? ? ? ? canvasTxt.fill(); ? ? ? } ? ? }
4、重寫
const overwrite = ()=> { ? ? ? canvasTxt.clearRect( ? ? ? ? 0, ? ? ? ? 0, ? ? ? ? canvasF.value.width, ? ? ? ? canvasF.value.height ? ? ? ); ? ? ? points = []; ? ? ? isDraw.value = false; //簽名標(biāo)記 ? ? }
5、保存圖片
function seaveImages() { ? ? if(isDraw.value){ ? ? ? ?strDataURI = canvasF.value.toDataURL("image/png"); ? ? ? ?console.log(strDataURI) ? ? ? ?cxt.emit("autographConfirm", { ? ? ? ? baseCode:strDataURI, ? ? ? }); ? ? }else{ ? ? ? console.log(Toast); ? ? ? Toast('您還沒有簽名') ? ? } ? }
最后附上完整代碼:
<template> ? <div class="signName" :style="{top:0,left:differ+'px'}"> ? ? <div class="close" @click="close"><img src="../assets/images/close.png" alt=""></div> ? ?<div class="autographBox"> ? ? ? <div ref="canvasHW"> ? ? ? ?<canvas ? ? ? ? @touchstart="touchStart($event)" ? ? ? ? @touchmove="touchMove($event)" ? ? ? ? @touchend="touchEnd($event)" ? ? ? ? ref="canvasF" ? ? ? ></canvas> ? ? ? </div> ? ? ? <p v-if="!isDraw">請本人簽名</p> ? ?</div> ? ? <div class="autographBtn"> ? ? ? <div @click="overwrite">重簽</div> ? ? ? <div @click="seaveImages">確定</div> ? ? </div> ? </div> </template> <script> import { ref, onMounted } from "vue"; import { Toast } from "vant"; export default { ? name: "index", ? setup(props,cxt) { ? ? var differ = ref(document.documentElement.clientWidth) ? ?var canvasF = ref(null); ? ?var canvasHW = ref(null); ? ?var canvasTxt = null; //畫布 ? ?var points = []; // 記錄點(diǎn) ? ?var isDraw = ref(false); //簽名標(biāo)記 ? ?var startX = 0; //開始坐標(biāo)x ? ?var startY = 0;//開始坐標(biāo)y ? ?var moveY= 0; ? ?var moveX= 0; ? ?var strDataURI ='' // 保存的canvas圖像 ? ? onMounted(() =>{ ? ? ? let canvas =canvasF.value; ? ? ? canvas.height = canvasHW.value.offsetHeight - 10; ? ? ? canvas.width = canvasHW.value.offsetWidth - 10; ? ? ? canvasTxt = canvas.getContext("2d"); ? ? ? canvasTxt.strokeStyle = '#333'; ? ? ? canvasTxt.lineWidth = '3'; ? ? })? ? ? const touchStart = (ev) => { ? ? ? ev = ev || event; ? ? ? ev.preventDefault(); ? ? ? if (ev.touches.length == 1) { ? ? ? ? isDraw.value = true; //簽名標(biāo)記 ? ? ? ? let obj = { ? ? ? ? ? x: ev.targetTouches[0].clientY, ? ? ? ? ? y: differ.value- ev.targetTouches[0].clientX - (differ.value*0.1) ? ? ? ? }; //y的計(jì)算值中:document.body.offsetHeight*0.5代表的是除了整個(gè)畫板signatureBox剩余的高,this.$refs.canvasHW.offsetHeight*0.1是畫板中標(biāo)題的高 ? ? ? ? startX = obj.x; ? ? ? ? startY = obj.y; ? ? ? ? canvasTxt.beginPath();//開始作畫 ? ? ? ? points.push(obj);//記錄點(diǎn) ? ? ? } ? ? } ? ?const touchMove = (ev)=> { ? ? ? ev = ev || event; ? ? ? ev.preventDefault(); ? ? ? if (ev.touches.length == 1) { ? ? ? ? let obj = { ? ? ? ? ? x: ev.targetTouches[0].clientY, ? ? ? ? ? y: differ.value- ev.targetTouches[0].clientX - (differ.value*0.1) ? ? ? ? }; ? ? ? ? moveY = obj.y; ? ? ? ? moveX = obj.x; ? ? ? ? canvasTxt.moveTo(startX, startY);//移動(dòng)畫筆 ? ? ? ? canvasTxt.lineTo(obj.x, obj.y);//創(chuàng)建線條 ? ? ? ? canvasTxt.stroke();//畫線 ? ? ? ? startY = obj.y; ? ? ? ? startX = obj.x; ? ? ? ? points.push(obj);//記錄點(diǎn) ? ? ? } ? ? } ? ? const touchEnd = (ev)=> { ? ? ? ev = ev || event; ? ? ? ev.preventDefault(); ? ? ? if (ev.touches.length == 1) { ? ? ? ? let obj = { ? ? ? ? ? x: ev.targetTouches[0].clientY, ? ? ? ? ? y: differ.value- ev.targetTouches[0].clientX - (differ.value*0.1) ? ? ? ? }; ? ? ? ? points.push(obj);//記錄點(diǎn) ? ? ? ? points.push({ x: -1, y: -1 });//記錄點(diǎn) ? ? ? ? canvasTxt.closePath();//收筆 ? ? ? ? canvasTxt.fill(); ? ? ? } ? ? } ? ? const overwrite = ()=> { ? ? ? canvasTxt.clearRect( ? ? ? ? 0, ? ? ? ? 0, ? ? ? ? canvasF.value.width, ? ? ? ? canvasF.value.height ? ? ? ); ? ? ? points = []; ? ? ? isDraw.value = false; //簽名標(biāo)記 ? ? } ? function seaveImages() { ? ? if(isDraw.value){ ? ? ? ?strDataURI = canvasF.value.toDataURL("image/png"); ? ? ? ?console.log(strDataURI) ? ? ? ?cxt.emit("autographConfirm", { ? ? ? ? baseCode:strDataURI, ? ? ? }); ? ? }else{ ? ? ? console.log(Toast); ? ? ? Toast('您還沒有簽名') ? ? } ? } ? function close(){ ? ? cxt.emit("close", { ? ? ? closeFlag:false, ? ? }); ? } ? ? return { ? ? ? differ, ? ? ? canvasF, ? ? ? canvasHW, ? ? ? isDraw, ? ? ? touchStart, ? ? ? touchMove, ? ? ? touchEnd, ? ? ? overwrite, ? ? ? seaveImages, ? ? ? close ? ? }; ? }, }; </script> <style scoped> .signName{ ? position: fixed; ? height: 100vw; ? width: 100vh; ? background-color: #fff; ? transform:rotate(90deg); ? -webkit-transform:rotate(90deg); ? transform-origin: left top; ? z-index: 1000; ? /* top:0; ? left: 0; */ } .close{ ? width: 100%; ? height: 10%; ? padding-left: 2.5rem; ? padding-top: 1.2rem; } .close img{ ? width: 2rem; } ?.autographBox{ ? width: 100%; ? height: 80%; ? position: relative; }? .autographBox div{ ? width: 100%; ? height: 100%; } .autographBox canvas{ ? width: 100%; ? height: 100%; } .signName p{ ? position: absolute; ? top:50%; ? left: 50%; ? transform: translate(-50%,-50%); ? font-size: 4rem; ? font-weight: bolder; ? color:#436CDF; ? opacity: 0.1; }? .autographBtn{ ? width: 100%; ? height: 10%; ? display: flex; ? justify-content: center; ? align-items: center; } .autographBtn div{ ? width: 50%; ? height: 100%; ? color: #fff; ? display: flex; ? justify-content: center; ? align-items: center; ? font-size: 1.3rem; } .autographBtn div:first-child{ ? opacity: 0.4; ? background: ?-webkit-linear-gradient(top, #728CFD 0%,#5C7EFE 100%); } .autographBtn div:last-child{ ? background: ?-webkit-linear-gradient(top, #728CFD 0%,#5C7EFE 100%); } </style>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue 動(dòng)態(tài)樣式綁定 class/style的寫法小結(jié)
這篇文章主要介紹了vue 動(dòng)態(tài)樣式綁定 class/style的寫法小結(jié),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03vue3?v-bind="$attrs"繼承組件全部屬性的解決方案
這篇文章主要介紹了vue3?v-bind=“$attrs“?繼承組件全部屬性的解決方案,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06自帶氣泡提示的vue校驗(yàn)插件(vue-verify-pop)
這篇文章主要為大家詳細(xì)介紹了自帶氣泡提示的vue校驗(yàn)插件,vue-verify-pop的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04vue中使用localstorage來存儲(chǔ)頁面信息
這篇文章主要介紹了vue中使用localstorage來存儲(chǔ)頁面信息,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11總結(jié)4個(gè)方面優(yōu)化Vue項(xiàng)目
在本篇文章里我們給大家整理了一篇關(guān)于優(yōu)化VUE項(xiàng)目的四個(gè)總要點(diǎn),對此有需要的朋友們學(xué)習(xí)下天。2019-02-02