手写签名(vue2+vant2)

先看效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
*直接贴代码 *
使用签名的页面文件

<template>
  <div class="about">
    <h1>This is an about1 page</h1>
    <div>
      <span class="danger">*</span>
      手写签名
    </div>
    <div class="disColumn">
      <img
        v-if="signvalue"
        :src="signvalue"
        class="nullSign"
        @click="signCompentShow"
      />
      <div v-else class="nullSign" @click="signCompentShow" />
    </div>
      <van-popup
        v-model="signPopup"
        close-on-popstate
      >
        <CostomSignToImg
          v-show="signPopup"
          ref="costomSignToImg"
          :cancel="cancel"
          :confirm="confirm"
        />
      </van-popup>
  </div>
</template>

<script>
import CostomSignToImg from "./CostomSignToImg.vue";
export default {
  components:{
    CostomSignToImg
  },
  data() {
    return {
      signvalue: false,
      signPopup: false
    };
  },
  methods: {
    
    signCompentShow() {
      console.log(111);
      this.scrollTop = document.documentElement.scrollTop;
      document.body.scrollTop = document.documentElement.scrollTop = 0;
      setTimeout(() => {
        this.signPopup = true;
      }, 100);
    },
    cancel() {
      document.body.scrollTop = document.documentElement.scrollTop = this.scrollTop;
      this.signPopup = false;
    },
    confirm(img, a) {
      document.body.scrollTop = document.documentElement.scrollTop = this.scrollTop;
      this.signPopup = false;
      console.log(img);
      console.log(a);
      this.signvalue = a;
      this.blob = img;
    },
    
  
  },
};
</script>

<style>
.questItem {
  padding: 0.625rem;
}

/* /deep/ .van-checkbox__label {
  color: #f76a38;
} */

.nullSign {
  background: #ebebeb;
  height: 6.25rem;
  width: 80vw;
  margin: 0.625rem auto 0 auto;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

.searchLi:hover {
  background-color: var(--color);
  color: #fff;
}

.searchBox {
  height: 9.375rem;
}
</style>

签名的组件

<template>
  <div ref="container" class="container">
      <canvas ref="myCanvas"></canvas>
      <div class="control-ops control " ref="control" style="justify-content: space-around">
          <van-button type="default" @click="onCancel">返回</van-button>
          <van-button type="default" @click="clearArea">重新签名</van-button>
          <van-button type="default" @click="onConfirm">确认</van-button>
      </div>
  </div>
</template>

<script>

  export default {
      props: ['confirm', 'cancel'],
      data() {
          return {
              lastX: null,
              lastY: null,
              initialized: false,
              orientation: "portrait",
              isSigned:false,
          };
      },
      mounted() {
          var mql = window.matchMedia("(orientation: portrait)");
          this.onMatchMeidaChange(mql);
          mql.addListener(this.onMatchMeidaChange);
      },
      methods: {
        getIsSigned(){
          console.log(this.isSigned);
          sessionStorage.setItem("isSigned",this.isSigned);
          return this.isSigned;
        },
          onMatchMeidaChange(mql) {
              if (mql.matches) {
                  this.orientation = "portrait";
              } else {
                  this.orientation = "landscape";
              }
              this.$nextTick(this.init);
          },
          onConfirm() {
              const c = this.$refs.myCanvas;
              let image = c.toDataURL("image/png");
              //得到生成后的签名base64位  url 地址
              c.toBlob(async blob => {
                  const url = URL.createObjectURL(blob);
                  console.log(url, 'url');
                  if (this.orientation === "portrait") {
                      image = await this.rotateImage(url);
                  } else {
                      this.confirm(blob, image);
                  }
                  URL.revokeObjectURL(url);
              });
              this.clearArea()
          },
          onCancel() {
              this.clearArea()
              this.cancel();
          },
          clearArea() {
              var c = this.$refs.myCanvas;
              var ctx = c.getContext("2d");
              // Use the identity matrix while clearing the canvas
              ctx.setTransform(1, 0, 0, 1, 0, 0);
              ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
          },
          rotateImage(url) {
              let that =this
              const width = window.innerWidth;
              const height = window.innerHeight;
              const canvas = document.createElement("canvas");
              canvas.width = height;
              canvas.height = width;
              const ctx = canvas.getContext("2d");
              ctx.rotate(-Math.PI / 2);
              ctx.translate(-width, 0);
              const image = new Image();
              image.src = url;
              image.setAttribute("crossOrigin", "anonymous");
              return new Promise((resolve, reject) => {
                  image.onload = function () {
                      ctx.drawImage(this, 0, 0, width, height);
                      canvas.toBlob(async blob => {
                          that.confirm(blob, canvas.toDataURL("image/png"));
                      });
                      resolve(canvas.toDataURL("image/png"));
                  };
                  image.onerror = e => {
                      reject(e);
                  };
              });
          },
          setControl() {
        
          },
          init() {
              const width = window.innerWidth;
              const height = window.innerHeight;
              var mousePressed = false;
              var c = this.$refs.myCanvas;
              const ctx = c.getContext("2d");
              const squareLen = Math.max(width, height);
              c.setAttribute("width", `${width}px`);
              c.setAttribute("height", `${height - 4}px`);
              ctx.moveTo(0, 0);
              ctx.fillStyle = "#fff";
              ctx.fillRect(0, 0, squareLen, squareLen);
              this.setControl();
              var vm = this;

              // 触摸屏
              //签名开始
              c.addEventListener(
                  "touchstart",
                  function (event) {
                      if (event.targetTouches.length == 1) {
                          event.preventDefault(); // 阻止浏览器默认事件,重要
                          var touch = event.targetTouches[0];
                          mousePressed = true;
                          vm.draw(
                              touch.pageX - this.offsetLeft,
                              touch.pageY - this.offsetTop,
                              false
                          );
                          this.isSigned = true;
          sessionStorage.setItem("isSigned",this.isSigned);
                      }
                  },
                  false
              );
          //签名移动开始
              c.addEventListener(
                  "touchmove",
                  function (event) {
                      if (event.targetTouches.length == 1) {
                          event.preventDefault(); // 阻止浏览器默认事件,重要
                          var touch = event.targetTouches[0];
                          if (mousePressed) {
                              vm.draw(
                                  touch.pageX - this.offsetLeft,
                                  touch.pageY - this.offsetTop,
                                  true
                              );
                          this.isSigned = true
                          
          sessionStorage.setItem("isSigned",this.isSigned);
                          console.log(sessionStorage.getItem("isSigned"));
                          }
                      }
                  },
                  false
              );

              c.addEventListener(
                  "touchend",
                  function (event) {
                      if (event.targetTouches.length == 1) {
                          event.preventDefault(); // 阻止浏览器默认事件,防止手写的时候拖动屏幕,重要
                          // var touch = event.targetTouches[0];
                          mousePressed = false;
                      }
                  },
                  false
              );

              //		   鼠标
              c.onmousedown = function (event) {
                  mousePressed = true;
                  vm.draw(
                      event.pageX - this.offsetLeft,
                      event.pageY - this.offsetTop,
                      false
                  );
                  this.isSigned = true
              };

              c.onmousemove = function (event) {
                  if (mousePressed) {
                      vm.draw(
                          event.pageX - this.offsetLeft,
                          event.pageY - this.offsetTop,
                          true
                      );
                          this.isSigned = true
                  }
              };

              c.onmouseup = function () {
                  mousePressed = false;
                  this.isSigned = true
                  console.log(this.isSigned);
              };

              
          },
          draw(x, y, isDown) {
              var c = this.$refs.myCanvas;
              var ctx = c.getContext("2d");
              if (isDown) {
                  ctx.beginPath();
                  ctx.strokeStyle = "#666"; //颜色
                  ctx.lineWidth = 3; //线宽
                  ctx.lineJoin = "round";
                  ctx.moveTo(this.lastX, this.lastY);
                  ctx.lineTo(x, y);
                  ctx.closePath();
                  ctx.stroke();
              }
              this.lastX = x;
              this.lastY = y;
          }
      }
  };
</script>

<style >
  canvas {
      background: #fff;
  }

  .container {
      position: relative;
  }

  .control {
      position: absolute;
      bottom: 0;
      background: #ddd;
  }

  @media screen and (orientation: portrait) {
      .control {
          left: 0;
          top: 0;
          display: flex;
          flex-direction: column;
          height: 100vh;
      }
      .van-button {
          transform: rotate(90deg);
      }
  }

  @media screen and (orientation: landscape) {
      .control {
          left: 0;
          width: 100%;
      }
  }
</style>

最终的签名图片是base64格式的
在父组件的 confirm函数里面我也有打印

终-----------

### 集成 e签宝实现 UniApp 电子签名 #### 准备工作 为了在 UniApp 中集成 e签宝来实现电子签名功能,开发者需先完成一些准备工作。这包括注册成为 e签宝的开发者账号并获取相应的 API Key 和 Secret Key[^2]。 #### 创建项目结构 创建一个新的 UniApp 项目用于集成 e签宝 SDK 或者 RESTful API 接口调用。确保项目的 `manifest.json` 文件中已经配置好网络请求权限以及 HTTPS 请求白名单设置以便能够顺利访问外部服务[^1]。 #### 初始化环境变量 将从 e签宝获得的应用凭证保存至 `.env.development` 或其他安全的地方作为环境变量管理: ```bash E_SIGNATURE_APP_KEY=your_app_key_here E_SIGNATURE_SECRET_KEY=your_secret_key_here ``` #### 编写业务逻辑代码 编写 JavaScript 方法来进行身份验证、发起签署流程等操作。这里给出一个简单的例子展示如何通过 axios 库发送 HTTP POST 请求给 e签宝服务器以启动合同签署过程: ```javascript import axios from 'axios'; const esignApiUrl = process.env.VUE_APP_E_SIGN_API_URL; async function startSignProcess(contractId, userId) { try { const response = await axios.post(`${esignApiUrl}/v1/sign/start`, { contract_id: contractId, user_id: userId }, { headers: { Authorization: `Bearer ${process.env.E_SIGNATURE_ACCESS_TOKEN}` } }); console.log('Start sign process result:', response.data); return response.data; } catch (error) { console.error(error.message); throw new Error(`Failed to start signing process for contract ID:${contractId}`); } } ``` 此函数接收两个参数:一个是待签署的合同编号 (`contractId`);另一个是要执行签署动作用户的唯一标识符 (`userId`)。它会向指定 URL 发送带有必要数据的有效负载,并返回来自远程服务器的结果信息。 #### 用户界面设计 对于实际应用来说,还需要构建友好的用户交互页面让用户可以方便地查看待签署文件内容、输入个人信息(如姓名、日期)、绘制手写签名等等。这部分可以通过 HTML/CSS 结合 Vant Weapp 组件库快速搭建起来[^3]。 #### 测试与部署 最后一步是对整个应用程序进行全面测试,确认各个模块之间协同工作的正确性和稳定性之后再考虑上线发布事宜。建议使用真机调试工具配合官方提供的沙盒环境进行充分的功能性检验[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值