因业务需求,前段时间写了一个电子签名组件,在这里记录一下,绘图需求,首先肯定需要使用
canvas标签,考虑到在移动端使用,所以选择使用touch事件。
首先奉上html结构(该组件为横屏展示):
<div class="signName" :style="{top:0,left:differ+'px'}">
<div class="close" @click="close"><img src="../assets/images/" 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()
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 =;
= - 10;
= - 10;
canvasTxt = ("2d");
= '#333';
= '3';
})
主要事件方法如下:
-
touchstart
const touchStart = (ev) => { ev = ev || event; (); if ( == 1) { = true; //签名标记 let obj = { x: [0].clientY, y: - [0].clientX - (*0.1) }; //y的计算值中:*0.5代表的是除了整个画板signatureBox剩余的高,this.$*0.1是画板中标题的高 startX = ; startY = ; ();//开始作画 (obj);//记录点 } }
-
touchmove
const touchMove = (ev)=> { ev = ev || event; (); if ( == 1) { let obj = { x: [0].clientY, y: - [0].clientX - (*0.1) }; moveY = ; moveX = ; (startX, startY);//移动画笔 (, );//创建线条 ();//画线 startY = ; startX = ; (obj);//记录点 } }
-
touchend
const touchEnd = (ev)=> { ev = ev || event; (); if ( == 1) { let obj = { x: [0].clientY, y: - [0].clientX - (*0.1) }; (obj);//记录点 ({ x: -1, y: -1 });//记录点 ();//收笔 (); } }
-
重写
const overwrite = ()=> { ( 0, 0, , ); points = []; = false; //签名标记 }
-
保存图片
function seaveImages() { if(){ strDataURI = ("image/png"); (strDataURI) ("autographConfirm", { baseCode:strDataURI, }); }else{ (Toast); Toast('您还没有签名') } }
最后附上完整代码:
<template>
<div class="signName" :style="{top:0,left:differ+'px'}">
<div class="close" @click="close"><img src="../assets/images/" 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()
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 =;
= - 10;
= - 10;
canvasTxt = ("2d");
= '#333';
= '3';
})
const touchStart = (ev) => {
ev = ev || event;
();
if ( == 1) {
= true; //签名标记
let obj = {
x: [0].clientY,
y: - [0].clientX - (*0.1)
}; //y的计算值中:*0.5代表的是除了整个画板signatureBox剩余的高,this.$*0.1是画板中标题的高
startX = ;
startY = ;
();//开始作画
(obj);//记录点
}
}
const touchMove = (ev)=> {
ev = ev || event;
();
if ( == 1) {
let obj = {
x: [0].clientY,
y: - [0].clientX - (*0.1)
};
moveY = ;
moveX = ;
(startX, startY);//移动画笔
(, );//创建线条
();//画线
startY = ;
startX = ;
(obj);//记录点
}
}
const touchEnd = (ev)=> {
ev = ev || event;
();
if ( == 1) {
let obj = {
x: [0].clientY,
y: - [0].clientX - (*0.1)
};
(obj);//记录点
({ x: -1, y: -1 });//记录点
();//收笔
();
}
}
const overwrite = ()=> {
(
0,
0,
,
);
points = [];
= false; //签名标记
}
function seaveImages() {
if(){
strDataURI = ("image/png");
(strDataURI)
("autographConfirm", {
baseCode:strDataURI,
});
}else{
(Toast);
Toast('您还没有签名')
}
}
function close(){
("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>