本文实例为大家分享了vue3.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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

vue3.0实现移动端电子签名组件的更多相关文章

  1. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  2. vue自定义加载指令v-loading占位图指令v-showimg

    这篇文章主要为大家介绍了vue自定义加载指令和v-loading占位图指令v-showimg的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  3. vue使用动画实现滚动表格效果

    这篇文章主要为大家详细介绍了vue使用动画实现滚动表格效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  4. 关于Vue 监控数组的问题

    这篇文章主要介绍了Vue 监控数组的示例,主要包括Vue 是如何追踪数据发生变化,Vue 如何更新数组以及为什么有些数组的数据变更不能被 Vue 监测到,对vue监控数组知识是面试比较常见的问题,感兴趣的朋友一起看看吧

  5. Vue子组件props从父组件接收数据并存入data

    这篇文章主要介绍了Vue子组件props从父组件接收数据并存入data的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  6. Vue h函数的使用详解

    本文主要介绍了Vue h函数的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  7. VUE响应式原理的实现详解

    这篇文章主要为大家详细介绍了VUE响应式原理的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  8. vue+Element ui实现照片墙效果

    这篇文章主要为大家详细介绍了vue+Element ui实现照片墙效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. vue+elemet实现表格手动合并行列

    这篇文章主要为大家详细介绍了vue+elemet实现表格手动合并行列,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. iview+vue实现导入EXCEL预览功能

    这篇文章主要为大家详细介绍了iview+vue实现导入EXCEL预览功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部