溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

vue3.0怎么實(shí)現(xiàn)移動(dòng)端電子簽名組件

發(fā)布時(shí)間:2022-08-30 09:56:22 來源:億速云 閱讀:267 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“vue3.0怎么實(shí)現(xiàn)移動(dòng)端電子簽名組件”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“vue3.0怎么實(shí)現(xiàn)移動(dòng)端電子簽名組件”吧!

因業(yè)務(wù)需求,前段時(shí)間寫了一個(gè)電子簽名組件,在這里記錄一下,繪圖需求,首先肯定需要使用

canvas標(biāo)簽,考慮到在移動(dòng)端使用,所以選擇使用touch事件。

首先奉上html結(jié)構(gòu)(該組件為橫屏展示):

<div class="signName" :>
    <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">請(qǐng)本人簽名</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" :>
    <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">請(qǐng)本人簽名</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>

到此,相信大家對(duì)“vue3.0怎么實(shí)現(xiàn)移動(dòng)端電子簽名組件”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI