vue3.0移动端电子签名组件
捕风的紫色鸢尾 人气:0因业务需求,前段时间写了一个电子签名组件,在这里记录一下,绘图需求,首先肯定需要使用
canvas标签,考虑到在移动端使用,所以选择使用touch事件。
首先奉上html结构(该组件为横屏展示):
<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 = []; // 记录点 var isDraw = ref(false); //签名标记 var startX = 0; //开始坐标x var startY = 0;//开始坐标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; //签名标记 let obj = { x: ev.targetTouches[0].clientY, y: differ.value- ev.targetTouches[0].clientX - (differ.value*0.1) }; //y的计算值中:document.body.offsetHeight*0.5代表的是除了整个画板signatureBox剩余的高,this.$refs.canvasHW.offsetHeight*0.1是画板中标题的高 startX = obj.x; startY = obj.y; canvasTxt.beginPath();//开始作画 points.push(obj);//记录点 } }
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);//移动画笔 canvasTxt.lineTo(obj.x, obj.y);//创建线条 canvasTxt.stroke();//画线 startY = obj.y; startX = obj.x; points.push(obj);//记录点 } }
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);//记录点 points.push({ x: -1, y: -1 });//记录点 canvasTxt.closePath();//收笔 canvasTxt.fill(); } }
4、重写
const overwrite = ()=> { canvasTxt.clearRect( 0, 0, canvasF.value.width, canvasF.value.height ); points = []; isDraw.value = false; //签名标记 }
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 = []; // 记录点 var isDraw = ref(false); //签名标记 var startX = 0; //开始坐标x var startY = 0;//开始坐标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; //签名标记 let obj = { x: ev.targetTouches[0].clientY, y: differ.value- ev.targetTouches[0].clientX - (differ.value*0.1) }; //y的计算值中:document.body.offsetHeight*0.5代表的是除了整个画板signatureBox剩余的高,this.$refs.canvasHW.offsetHeight*0.1是画板中标题的高 startX = obj.x; startY = obj.y; canvasTxt.beginPath();//开始作画 points.push(obj);//记录点 } } 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);//移动画笔 canvasTxt.lineTo(obj.x, obj.y);//创建线条 canvasTxt.stroke();//画线 startY = obj.y; startX = obj.x; points.push(obj);//记录点 } } 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);//记录点 points.push({ x: -1, y: -1 });//记录点 canvasTxt.closePath();//收笔 canvasTxt.fill(); } } const overwrite = ()=> { canvasTxt.clearRect( 0, 0, canvasF.value.width, canvasF.value.height ); points = []; isDraw.value = false; //签名标记 } 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>
加载全部内容