vue3.0实现移动端电子签名组件

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

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

(0)

相关推荐

  • vue 使用 canvas 实现手写电子签名

    功能 兼容 PC 和 Mobile: 画布自适应屏幕大小变化(窗口缩放.屏幕旋转时画布无需重置,自动校正坐标偏移): 自定义画布尺寸(导出图尺寸),画笔粗细.颜色,画布背景色: 支持裁剪 (针对需求:有的签字需要裁剪掉四周空白). 导出图片格式为 base64 : 示例demo 安装 npm install vue-esign --save 使用 main.js 中引入 import vueEsign from 'vue-esign' Vue.use(vueEsign) 页面中使用 必须设置 r

  • Vue Canvas实现电子签名

    最近再做移动端电子签名,Vue+Canvas实现,移动端.PC端均可,也可以从github下载 . 我在做这个功能的时候参考了 这个代码,但是在移动端光标与实际划线有偏移,我在我的代码中修正了这个问题. 代码 <template>       <section class="signature">           <div class="signatureBox">               <div class=&q

  • 使用vue实现一个电子签名组件的示例代码

    在生活中我们使用到电子签名最多的地方可能就是银行了,每次都会让你留下大名.今天我们就要用vue实现一个电子签名的面板 想要绘制图形,第一步想到的就是使用canvas标签,在之前的文章里我们使用canvas实现了一个前端生成图形验证码的组件,被吐槽不够安全,那么这个电子签名组件想必不会被吐槽了吧~ canvas <canvas> 标签是 HTML 5 中的新标签. <canvas> 标签只是图形容器,您必须使用脚本来绘制图形. canvas标签本身是没有绘图能力的,所有的绘制工作必须

  • vue3.0实现移动端电子签名组件

    本文实例为大家分享了vue3.0实现移动端电子签名组件的具体代码,供大家参考,具体内容如下 因业务需求,前段时间写了一个电子签名组件,在这里记录一下,绘图需求,首先肯定需要使用 canvas标签,考虑到在移动端使用,所以选择使用touch事件. 首先奉上html结构(该组件为横屏展示): <div class="signName" :style="{top:0,left:differ+'px'}">     <div class="clo

  • vue3.0封装轮播图组件的步骤

    接着上一篇文章,熟悉vue3.0的基本用法,和使用一段时间以后,开始准备开发适用于vue3.0使用的pc端的组件库.会陆续跟新一些组件库的写法和注意事项,有兴趣的同学可以多多关注哦,不多bb,开始. 开发一个轮播图组件,适用pc端,(暂无考虑app), 使用于vue3.0 + TS 大致的实现效果是这样: 图片自由轮播,对应圆点图片跳转,左右指示器跳转等.暴露以下options配置: 以上是主要的options,下面展开来说一下具体如何封装. 一:封装思想 在vue3.0和vue2.0中封装组件

  • vue3.0 CLI - 2.1 - component 组件入门教程

    我的 github 地址 - vue3.0Study - 阶段学习成果都会建立分支. 进入 src 文件夹,这是实际都工程文件夹,其他文件夹以及文件以后在了解. 3个文件夹  assets - 各类静态资源文件夹 - 比如 图片, css 文件等.  components - 组件文件夹, 组件是 vue 等 MVC 框架等核心概念,自行了解含义. view - 视图文件夹. 5个文件  app.vue.main.js - 主视图.配合 main.js 成为 vue 程序的主入口.router.

  • vue3.0 CLI - 2.4 - 新组件 Forms.vue 中学习表单

    我的 github 地址 - vue3.0Study- 阶段学习成果都会建立分支. 新组件 - 新路由 Forms.vue ( 下面仅介绍如何创立, 不进行介绍 ) : <template><div class="form"> <input v-model="message" placeholder="edit me"> <p>Message is: {{ message }}</p>

  • vue3.0+vite2实现动态异步组件懒加载

    创建一个vite项目 性能决定成败;vite确实快: cmd 命令行(默认你已经安装了node & npm),执行npm init @vitejs/app vue-study – --template vue: cd至vue-study,npm install(安装依赖); npm run dev(启动项目): 创建组件 新建一个目录为pages,pages下面再新建一个目录contents,contens下面可以新建具体的组件目录页面,此时目录结构为 App.vue <template&g

  • vue3.0实现复选框组件的封装

    本文实例为大家分享了vue3.0实现复选框组件封装的具体代码,供大家参考,具体内容如下 大致步骤: 实现组件本身的选中与不选中效果 实现组件的v-model指令 改造成 @vueuse/core 的函数写法 <!-- 组件基本样式 --> <template> <div class="xtx-checkbox" @click="changeChecked()"> <i v-if="checked" cla

  • vue3.0 CLI - 2.5 - 了解组件的三维

    我的 github 地址 - vue3.0Study - 阶段学习成果都会建立分支. 问答 1.vue 组件有什么? 为什么要加上 vue,因为不同的 MVC 框架,东西不一样,不过基本的功能都有. 组件有 data.computed.watch.methods 以及生命周期钩子等.对于入门者来说,先搞清楚这些是什么东西. data 属性经过前面几篇文章的学习,对其已有初步的了解. computed 是计算属性,前面也有了解. methods 组件方法,其实是专门定义函数的一个对象,这些函数最终

  • vue3.0 移动端二次封装van-uploader实现上传图片(vant组件库)

    1.前提:业务需求,最多上传6张图片,并可以实现本地预览 2.解决方法:使用vant组件库中的van-uploader实现 3.代码实现 template <div class="upload-oss"> <van-uploader :after-read="onRead" :before-read="beforeRead" :accept="fileType" v-model="fileList&

  • vue3.0搭配.net core实现文件上传组件

    在开发Web应用程序中,文件上传是经常用到的一个功能. 在Jquery时代,做上传功能,一般找jQuery插件就够了,很少有人去探究上传文件插件到底是怎么做的. 简单列一下我们要做的技术点和功能点 使用技术 客户端使用vue.js 3.0,并使用vue3新增的功能:Composition API ,服务器使用asp.net core 功能点 标签美化 文件预览 文件上传 服务器接收文件 文件选择美化 在标准的html文件选择标签,是十分不美观的.大概就是下图的样子 但是我们的设计师的设计图可不是

  • 基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

    之前有分享一个vue2.x移动端弹框组件,今天给大家带来的是Vue3实现自定义弹框组件. V3Popup 基于vue3.x实现的移动端弹出框组件,集合msg.alert.dialog.modal.actionSheet.toast等多种效果.支持20+种自定义参数配置,旨在通过极简的布局.精简的调用方式解决多样化的弹框场景. v3popup 在开发之初参考借鉴了Vant3.ElementPlus等组件化思想.并且功能效果和之前vue2.0保持一致. ◆ 快速引入 在main.js中全局引入v3p

随机推荐