Vue Sign-Canvas使用指南,JoeyChou

Vue Sign-Canvas使用指南

废话不多说,上项目和代码
 vue-sign-canvas项目地址: https://github.com/langyuxiansheng/vue-sign-canvas

在线演示: https://langyuxiansheng.github.io/vue-sign-canvas/

基础用法

因为 vue-sign-canvas 的包名被占用了,只好去掉一个前缀了....假如此轮子对你有帮助,请顺手star一下吧.o(* ̄︶ ̄*)o

开始使用! 下载安装npm包
npm i sign-canvas --save
//全局注册 main.js
import SignCanvas from 'sign-canvas';
 
Vue.use(SignCanvas);



组件模板使用

<template>
  <div class="g-nickname">
    <my-header title="设置签名"></my-header>
    <div class="setting-form mt10" style="margin-bottom: 68px;">
      <div class="form-list">
        <div class="flex mt30" style="text-align: center;color:red;font-size: 12px;margin: 20px 0px;">
            请在下面红色框内手写签名
        </div>
        <div class="flex" style="text-align: center;">
          <sign-canvas class="sign-canvas" ref="SignCanvas" :options="options" v-model="signImg"/>
        </div>
        <div class="flex" style="text-align: center;">
          <img v-if="!signImg&&imageUrl" class="view-image" :src="imageUrl" width="150">
          <img v-if="signImg" class="view-image" :src="signImg" width="150">
          <a class="login-btn btn-gray" @click="canvasClear()" v-if="signImg" style="width: 90px;font-size: 12px;">重新签署</a>
        </div>
        
        <div class="flex mt30" style="text-align: center;font-size: 12px;margin-top: 20px;line-height:32px;">
            <p style="color:red;">注:签名设计完成后,后续协议将自动根据签名进行签署</p>
            <p><input type="checkbox" id="checkbox" v-model="isCheck" :disabled="isCheckDis" />
                请确定并了解
                <a class="font-size14 font-blue" @click="proShow()">《用户须知协议指引》</a>
            </p>
        </div>
       </div>
        <a class="login-btn btn-blue" @click="uploadSign()">保存签名</a>
    </div>

    <div v-transfer-dom>
      <x-dialog v-model="showProtocol" class="dialog-Protocol">
        <div class="protocolContent">
          <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
            <el-tab-pane label="注册协议" name="first" v-html="protocolContent">注册协议</el-tab-pane>
            <el-tab-pane label="买跌委托投资协议" name="second" v-html="protocolContent1">-</el-tab-pane>
            <el-tab-pane label="买涨委托投资协议" name="third" v-html="protocolContent2">-</el-tab-pane>
          </el-tabs>
        </div>
        <a class="register-btn btn-gray mt10 mb10" v-show="isDisabled">{{buttonName}}</a>
        <a class="register-btn btn-blue mt10 mb10" @click="closeProtocol" v-show="isDisabled==false">{{buttonName}}</a>
      </x-dialog>
    </div>

  </div>
</template>

<script>
  import Vue from "vue";
  import SignCanvas from 'sign-canvas';
  import {upload,UpdateSign} from '@/assets/js/axios-api/UserAssets.js';
  import { GetAgreeMent } from "@/assets/js/axios-api/ArticalShows.js";
  Vue.use(SignCanvas);
  export default {
    data() {
      return {
        showProtocol:false,
        isDisabled:false,
        second:10,
        isCheck:false,
        isCheckDis:true,
        buttonName:'',
        activeName:'',
        protocolContent:'',
        protocolContent1:'',
        protocolContent2:'',
        callIndex:'',
        callCount1:0,
        callCount2:0,
        callCount3:0,
        nickName: '',
        signImg:'',
        signImgMin:'',
        imageUrl:'',
        options:{
          lastWriteSpeed: 1,  //书写速度 [Number] 可选
          lastWriteWidth: 1,  //下笔的宽度 [Number] 可选
          lineCap: 'round',   //线条的边缘类型 [butt]平直的边缘 [round]圆形线帽 [square]	正方形线帽
          lineJoin: 'round',  //线条交汇时边角的类型  [bevel]创建斜角 [round]创建圆角 [miter]创建尖角。
          canvasWidth: 360, //canvas宽高 [Number] 可选
          canvasHeight: 180,  //高度  [Number] 可选
          isShowBorder: false, //是否显示边框 [可选]
          bgColor: '#fcc', //背景色 [String] 可选 注:这背景色仅仅只是canvas背景,保存的图片仍然是透明的
          borderWidth: 1, // 网格线宽度  [Number] 可选
          borderColor: "#ff787f", //网格颜色  [String] 可选
          writeWidth: 2, //基础轨迹宽度  [Number] 可选
          maxWriteWidth: 5, // 写字模式最大线宽  [Number] 可选
          minWriteWidth: 5, // 写字模式最小线宽  [Number] 可选
          writeColor: '#101010', // 轨迹颜色  [String] 可选
          isSign: false, //签名模式 [Boolean] 默认为非签名模式,有线框, 当设置为true的时候没有任何线框
          imgType:'png'   //下载的图片格式  [String] 可选为 jpeg  canvas本是透明背景的
        }
      };
    },
    components: {},
    mounted() {
      this.imageUrl=this.$store.getters.getUserInfo.signPath;
      if (this.$store.getters.getUserInfo.nameTrue != 2) {
        this.$vux.alert.show({title: "提示",content: "您还未实名认证,请先实名认证",
          onHide() {this.$router.push("/personal/personalSet/realName");}
        });
      }
    },
    methods: {
      //自己定义data哈
      getCode(){
          let that = this;
          that.isDisabled = true;
          let interval = setInterval(function() {
          that.buttonName = "请至少阅读" + that.second + "秒";
          --that.second;
          if (that.second < 0) {
            that.buttonName = "确认";
            that.second = 10;
            that.isDisabled = false;
            clearInterval(interval);
          }
        }, 1000);
      },
      handleClick(tab, event) {
          //console.log(this.activeName+"***************"+tab.name+tab.key);
        },
        proShow(){
          this.activeName="first";
          this.lookProtocol('regpact');
          this.lookProtocol('tandzero');
          this.lookProtocol('tandd');
          this.getCode();
        },
      //查看协议
      lookProtocol(call) {
        let parameters = {
          "{moneyBorrow}": "",
        };
        this.callIndex=call;
        this.$vux.loading.show();
        GetAgreeMent(call, this.$store.getters.getUserInfo.id,parameters).then(
          res => {
            //console.log(res);
            if(call=="regpact")
              {
              this.protocolContent = res.Data.content;
              }
              if(call=="tandzero")
              {
              this.protocolContent1 = res.Data.content;
              }
              if(call=="tandd")
              {
              this.protocolContent2 = res.Data.content;
              }
            this.showProtocol = true;
            this.$vux.loading.hide();
          }
        );
      },
      closeProtocol(){
        switch(this.callIndex)
        {
          case 'tandd':
            this.callCount1=1;
            break;
          case 'tandzero':
            this.callCount2=1;
            break;
          case 'regpact':
            this.callCount3=1;
            break;
        }
        this.callCount1=1;
        this.callCount2=1;
        this.callCount3=1;
        if(this.callCount1==1&&this.callCount1==1&&this.callCount3==1)
        {
          this.isCheck=true;
          this.isCheckDis=false;
        }
        this.showProtocol = false;
      },
        /**
         * 清除画板
         */
        canvasClear(){
            this.$refs.SignCanvas.canvasClear();
        },
        /**
         * 保存图片
         */
        saveAsImg(){
            const img = this.$refs.SignCanvas.saveAsImg();
            alert(`image 的base64:${img}`);
        },
        /**
         * 下载图片
         */
        downloadSignImg(){
            this.$refs.SignCanvas.downloadSignImg();
        },
        base64ToFile(urlData, fileName) {
          let arr = urlData.split(",");
          let mime = arr[0].match(/:(.*?);/)[1];
          let suffix = mime.split("/")[1];
          let bstr = atob(arr[1]);
          let n = bstr.length;
          let u8arr = new Uint8Array(n);
          while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
          }
          return new File([u8arr], `${fileName}.${suffix}`, {
            type: mime
          });
        },
        uploadSign(){
          if (!this.signImg) {
            this.$vux.toast.show({type: 'cancel',text: '请先设计签名',time: 1000,width: '60%'});
            return;
          }
          if (this.isCheck == false) {
            this.$vux.toast.show({type: 'cancel',text: '请阅读并了解协议至少10秒以上',time: 3000,width: '80%'});
            return;
          }
          this.$vux.confirm.show({
            content: "签名设计完成后,后续协议将自动根据签名进行签署,您确定要继续吗?",
            confirmText: "确认",
            cancelText: "取消",
            onConfirm: () => {
              this.compressImg(this.signImg);
              console.log(this.signImgMin);
            }
          });
        },
        compressImg(sourceImgObj, quality, angleOffset, outputFormat) {
          let _this = this;
          quality = quality || 1;
          angleOffset = angleOffset || 0;
          var mimeType = outputFormat || "image/png";
          var Img = new Image(), dataURL = "";
            console.log(sourceImgObj);
          Img.src = sourceImgObj;
          Img.onload = function() {
            //var drawWidth = Img.naturalWidth,drawHeight = Img.naturalHeight;
            var drawWidth = 100,drawHeight = 50;
            // IOS 设备上 canvas 宽或高如果大于 1024,就有可能导致应用崩溃闪退
            // 因此这里需要缩放
            var maxSide = Math.max(drawWidth, drawHeight);
            if (maxSide > 256) {
              var minSide = Math.min(drawWidth, drawHeight);
              minSide = (minSide / maxSide) * 256;
              maxSide = 256;
              if (drawWidth > drawHeight) {
                drawWidth = maxSide;
                drawHeight = minSide;
              } else {
                drawWidth = minSide;
                drawHeight = maxSide;
              }
            }
            var cvs = document.createElement("canvas");
            var ctx = cvs.getContext("2d");
            if (angleOffset) {
              cvs.width = drawHeight;
              cvs.height = drawWidth;
              ctx.translate(drawHeight, 0);
              ctx.rotate((angleOffset * Math.PI) / 180);
            } else {
              cvs.width = drawWidth;
              cvs.height = drawHeight;
            }

            ctx.drawImage(Img, 0, 0, drawWidth, drawHeight);
            var newImageData = cvs.toDataURL(mimeType, quality || 1);
            console.log(newImageData);
            var file=_this.base64ToFile(newImageData,"签名");
              upload(file).then(res => {
                console.log(res);
                if (res.Result === 0) {
                  _this.imageUrl=res.Data.url;
                  _this.$vux.loading.show(); 
                  UpdateSign(_this.imageUrl).then(res => {
                      _this.$vux.loading.hide();
                      if (res.Result == 0) {  
                          _this.$vux.toast.show({type: 'ok',text: '签名保存成功',time: 1000,width: '60%'});        
                          _this.$router.push('/personal/personalSet/sign');
                      } else {   
                          _this.showCancel(res.Message)
                      }
                  });
                } else {
                  _this.$message({message: res.Message, type: 'error'});
                }
              });
          };
        }
    }
  }
</script>
<style lang="less">
.dialog-Protocol  {
  .weui-dialog 
  {
    max-width: 96%;
    width: 90%;
  }
  .protocolContent {
    padding: 10px;
    width: 100%;
    height:420px;
    overflow-y: scroll;
    text-align: left;
  }
}
  .g-nickname {
    font-size: 16px;

    .setting-form {
      background: #fff;
      padding: 0 10px;

      .form-list {
        li {
          height: 40px;
          line-height: 40px;
          border-bottom: 0;
          text-align: center;

          .input {
            border: 0;
            height: 30px;
            line-height: 30px;
            width: 100%;
            text-align: center;

          }
        }

        .tips {
          border-top: 2px solid #ececec;/*no*/

        }
      }
    }
  }

</style>