移动端横屏、竖屏签名面板

原理:signature_pad插件,canvas

<template>
  <div id="app">
    <button @click="handleClick">点击签名</button>
    <img :src="imgUrl" v-if="showImg" style="border:1px dashed #ccc;"/>
    <div class="sign-box" v-show="showSignature">
      <div class="bgc"></div>
      <div class="main-box">
        <span @click="cancelBgc" class="cancel">取消</span>
        <p class="title">签名</p>
        <p class="sub-title">请用正楷签下您的名字</p>
        <div :style="{width:w,height:h}" class="canvass">
          <canvas :id="uid" class="canvas" :data-uid="uid"></canvas>
        </div>
        <div id='reset' @click="clear">
          <span>清除</span>
        </div>
        <div @click="saveSign" class="next">确认</div>
      </div>
    </div>
  </div>
</template>

<script>
  /* eslint-disable */
  import SignaturePad from 'signature_pad';
  export default {
    data() {
      return {
        showSignature: false,
        showImg:false,
        sig: () => { },
        uid: 'canvas',
        option: {
          backgroundColor: 'rgb(255,255,255)',
          penColor: 'rgb(0, 0, 0)',
          minWidth: 0.8,
          maxWidth: 4
        },
        w: '94.6%',
        h: "240px",
      }
    },
    methods: {
      handleClick() {
        this.showSignature = true;
        this.$nextTick(() => {
          this.draw();
        })
      },
      // 签名
      draw() {
        var that = this;
        var canvas = document.getElementById(that.uid);
        that.sig = new SignaturePad(canvas, that.option);
        window.addEventListener('resize', that.resizeCanvas);
        that.resizeCanvas();
      },
      resizeCanvas() {
        var that = this
        var canvas = document.getElementById(that.uid);
        var url;
        var ratio = Math.max(window.devicePixelRatio || 1, 1);
        canvas.width = canvas.offsetWidth * ratio;
        canvas.height = canvas.offsetHeight * ratio;
        canvas.getContext('2d').scale(ratio, ratio);
        that.clear()
        !that.clearOnResize && url !== undefined && that.fromDataURL(url);
      },
      fromDataURL(url) {
        var that = this;
        that.sig.fromDataURL(url);
      },
      // 取消签名
      cancelBgc() {
        this.showSignature = false;
      },
      // 清除签名
      clear() {
        var that = this;
        that.sig.clear();
      },
      isEmpty() {
        var that = this;
        return that.sig.isEmpty();
      },
      // 保存签名
      saveSign() {
        var that = this;
        if (that.isEmpty()) {
          alert('请用正楷签下您的名字');
          return
        }
        var sign = {
          signature: that.sig.toDataURL().split(',')[1]
        }
        that.imgUrl = "data:image/png;base64," + sign.signature;
        that.showImg = true;
        that.showSignature = false;
      }
    }
  }
/* eslint-disable */
</script>

<style>
  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    color: #2c3e50;
    margin-top: 60px;
  }

  .canvass {
    margin: auto;
    background: #fff;
    border: 1px dashed #e5e5e5;
    border-radius: 8px;
    margin-top: 17px;
    position: relative;
  }

  #reset {
    text-align: center;
    font-size: 14px;
    color: #666666;
    margin-top: 26px;
    margin-bottom: 47px;

  }

  #reset img {
    width: 13px;
    height: 13px;
  }

  canvas {
    width: 100%;
    height: 100%;
  }

  .sign-box {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    min-height: 100vh;

  }

  .bgc {
    opacity: 0.7;
    background: #000000;
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    z-index: 5;
  }

  .main-box {
    height: 500px;
    width: 100%;
    background-color: #fff;
    position: absolute;
    bottom: 0;
    z-index: 10;

  }

  .cancel {
    position: absolute;
    font-size: 18px;
    color: #31A4FF;
    left: 15px;
    top: 16px;
  }

  .title {
    text-align: center;
    font-size: 18px;
    color: #333333;
    padding-top: 16px;
    padding-bottom: 4px;
  }

  .sub-title {
    font-size: 12px;
    color: #999999;
    text-align: center;
  }

  .next {
    border: 1px solid #31A4FF;
    height: 44px;
    text-align: center;
    line-height: 44px;
    font-size: 18px;
    color: #31A4FF;
    background: #fff;
    margin: 0 15px;
  }

  .footer {
    position: fixed;
    left: 0;
    bottom: 0;
    display: flex;
    justify-content: space-between;
    width: 100%;
  }

  .pre {
    width: 28%;
    margin-right: 1px;
    border-top: 1px solid #d6d6d6;
    color: #454545;
    background: #fff;
  }

  .share {
    width: 44%;
    border-top: 1px solid #d6d6d6;
    background: #66b9ff;
    color: #fff;
  }

  .nextOne {
    width: 28%;
    color: #fff;
    background: #31A4FF;
  }

  .commoncss {
    height: calc(110rem / 24);
    line-height: calc(110rem / 24);
    font-size: 1.6rem;
    text-align: center;
    box-sizing: border-box;
    margin-top: 1rem;
  }

  .hasLinkpre {
    margin-top: 1rem;
    background: #fff;
    width: 50%;
    height: calc(110rem / 24);
    line-height: calc(110rem / 24);
    font-size: 1.6rem;
    text-align: center;
    box-sizing: border-box;
    color: #454545;
  }

  .hasLinknextone {
    margin-top: 1rem;
    background: #31A4FF;
    width: 50%;
    height: calc(110rem / 24);
    line-height: calc(110rem / 24);
    font-size: 1.6rem;
    text-align: center;
    box-sizing: border-box;
    color: #fff;
  }
</style>

 

效果图:

 

 

横屏签名:

<template>
  <div id="app">
    <div class="content">
      <div class="btn" @click='toSign()'>点击此处签名</div>
      <img :src="'data:image/png;base64,'+appntSign" alt="" v-show="appntSign" id="signImg">
    </div>
    <div id="signContent" class='signBox' v-show="showSign">
      <div class="canvass">
        <canvas :id="uid" class="canvas" :data-uid="uid"></canvas>
      </div>
      <div class='footer'>
        <span @click="clear()">重签</span>
        <span @click="keepSign()" :class='{active:canSaveBtn}'>保存签名</span>
      </div>
    </div>
  </div>
</template>

<script>
  /* eslint-disable */
  import SignaturePad from 'signature_pad';
  export default {
    props: {
      showSignPage: {
        type: Boolean,
        default: false
      },
      relation: {
        type: String
      },
      sigOption: {
        type: Object,
        default: () => {
          return {
            backgroundColor: 'rgb(255,255,255)',
            penColor: 'rgb(0, 0, 0)'
          }
        }
      },
      w: {
        type: String,
        default: '90%'
      },
      h: {
        type: String,
        default: '250px'
      },
      clearOnResize: {
        type: Boolean,
        default: false
      }
    },
    data() {
      return {
        sig: () => { },
        option: {
          backgroundColor: 'rgb(255,255,255)',
          penColor: 'rgb(0, 0, 0)'
        },
        uid: '',
        signPerson: '投保人',
        time: 0,
        contNo: '',
        num: '',
        getdata: "",
        buttomShow: false,
        showSign: false,
        appntSign: '',
        canSaveBtn: false,
        needRotate: ''// 0 不旋转  1旋转
      }
    },
    created() {
      var _this = this
      this.uid = 'canvas' + _this._uid
      var sigOptions = Object.keys(_this.sigOption)
      for (var item of sigOptions) {
        _this.option[item] = _this.sigOption[item]
      }
    },
    watch: {
      // 险种信息监听
      showSignPage: {
        handler: function (val, oldVal) {
          this.resizeCanvas()
        },
        // 深度观察
        deep: true
      }
    },
    methods: {
      checkbox() {
        if (!this.appntSign) {
          this.buttomShow = false;
          Dialog.alert({
            message: '请签名'
          }).then(() => {
            // on close
          });
          return
        }
        this.buttomShow = !this.buttomShow;
      },
      draw() {
        var _this = this
        var canvas = document.getElementById(_this.uid)
        _this.sig = new SignaturePad(canvas, _this.option)
        window.addEventListener('resize', _this.resizeCanvas)
        _this.resizeCanvas()
        canvas.addEventListener('touchstart', function (e) {
          e.preventDefault()
          _this.canSave()
        })
        _this.setMark('请在此处使用正楷签名')
      },
      resizeCanvas() {
        var _this = this
        var canvas = document.getElementById(_this.uid)
        var url
        var ratio = Math.max(window.devicePixelRatio || 1, 1)
        canvas.width = canvas.offsetWidth * ratio
        canvas.height = canvas.offsetHeight * ratio
        canvas.getContext('2d').scale(ratio, ratio)
        _this.clear()
        !_this.clearOnResize && url !== undefined && _this.fromDataURL(url)
      },
      clear() {
        var _this = this
        _this.sig.clear()
        this.canSaveBtn = false
      },
      canSave() {
        this.canSaveBtn = true
      },
      toSign() {
        this.appntSign = ''
        this.showSign = true
        this.buttomShow = false;
        this.$nextTick(() => {
          this.draw()
        })
      },
      keepSign() { //保存签名
        var _this = this
        if (_this.isEmpty()) {
          return
        }
        _this.appntSign = _this.sig.toDataURL().split(',')[1]
        _this.showSign = false
        clearInterval(this.time)
        let id = _this.setWatermark('请在此处使用正楷签名');
        let rotate = document.getElementById(id).style.transform
        console.log(rotate)
        document.getElementById(id).style.display = 'none'
        let img = document.getElementById('signImg')
        debugger
        if (!rotate) {
          img.style.height = '65px'
          img.style.width = ''
          img.style.marginBottom = '-20px'
          img.style.marginLeft = '15px'
          img.style.transform = ''
          _this.needRotate = '0'
        } else {
          img.style.width = '65px'
          img.style.height = ''
          img.style.marginBottom = '-50px'
          img.style.marginLeft = '35px'
          img.style.transform = 'rotate(-90deg)'
          _this.needRotate = '1'
        }
      },
      cancel() {
        this.$emit('callback')
      },
      save(format) {
        var _this = this
        var str = "";
        if (!_this.appntSign) {
          Dialog.alert({
            message: '请签名'
          }).then(() => {
            // on close
          });
          return
        }
        let params = {
          contNo: _this.contNo,
          status: "02",
          imgBase64: _this.appntSign,
          index: "0",
          faceImageFlag: sessionStorage.getItem("faceImageFlag"),
          needRotate: _this.needRotate
        }
        questionnaireSubmit(params).then(result => {
          if (result && result.errorCode === "1") {
            _this.getdata = result.responseBody;
            str = _this.getdata.appntName + "," + _this.getdata.contNo + "," + _this.getdata.mainRiskName + "," + _this.getdata.addRiskName + "," + _this.getdata.statusLabel + "," + _this.getdata.visitDate + "," + _this.getdata.visitStatus + "," + _this.num;
            sessionStorage.setItem("camera", true); //true (正在进行中)  false  (下一次重新开始)
            _this.$router.push({ path: "end", query: { postdata: str } })
          } else {
            _this.$toast(result.errorMessage)
          }
        })
          .catch(rej => {
            console.log("签名", rej)
          })
        _this.buttomShow = !_this.buttomShow
      },
      fromDataURL(url) {
        var _this = this
        _this.sig.fromDataURL(url)
      },
      isEmpty() {
        var _this = this
        return _this.sig.isEmpty()
      },
      undo() {
        var _this = this
        var data = _this.sig.toData()
        if (data) {
          data.pop()
          _this.sig.fromData(data)
        }
      },
      setWatermark(str) { // 水印背景设置
        let id = '1.23452384164.123412416';
        if (document.getElementById(id) !== null) {
          document.body.removeChild(document.getElementById(id));
        }
        //创建一个画布
        let can = document.createElement('canvas');
        //设置画布的长宽
        can.width = 500;
        can.height = 100;

        let cans = can.getContext('2d');
        //旋转角度
        // cans.rotate(-15 * Math.PI / 180);
        cans.font = '40px Vedana';
        //设置填充绘画的颜色、渐变或者模式
        cans.fillStyle = 'rgba(200, 200, 200, 0.40)';
        //设置文本内容的当前对齐方式
        cans.textAlign = 'left';
        //设置在绘制文本时使用的当前文本基线
        cans.textBaseline = 'Middle';
        //在画布上绘制填色的文本(输出的文本,开始绘制文本的X坐标位置,开始绘制文本的Y坐标位置)
        cans.fillText(str, can.width / 8, can.height / 2);

        let div = document.createElement('div');
        div.id = id;
        div.style.pointerEvents = 'none';
        div.style.position = 'fixed';
        div.style.zIndex = '100000';
        let e = document.getElementsByClassName('canvas')[0]
        let height = e.offsetHeight
        let width = e.offsetWidth
        console.log(width)
        console.log(height)
        if (width > height) { // 横屏
          div.style.width = width + 'px';
          div.style.height = height + 'px';
          div.style.top = '20px';
          div.style.left = '15px';
        } else { // 竖屏
          div.style.width = height + 'px';
          div.style.height = width + 'px';
          div.style.top = 20 + (height - width) / 2 + 'px';
          div.style.right = 15 - (height - width) / 2 + 'px';
          div.style.transform = 'rotate(90deg)'
        }
        div.style.background = 'url(' + can.toDataURL('image/png') + ') center center no-repeat';
        document.body.appendChild(div);
        return id;
      },
      setMark(str) { // 显示水印背景
        let id = this.setWatermark(str);
        this.time = setInterval(() => {
          if (document.getElementById(id) === null) {
            id = this.setWatermark(str);
          }
        }, 500);
        window.onresize = () => {
          this.setWatermark(str);
        };
      }
    },
    mounted() {

    }
  }
/* eslint-disable */
</script>

<style>
  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    color: #2c3e50;
    margin-top: 60px;
  }

  .content {
    background: #fff;
    padding: 20px 23px 35px;
    min-height: 200px;

  }

  .content h4 {
    font-size: 16px;
    margin-bottom: 20px;
    color: #333;
  }

  .content p {
    color: #666;
    font-size: 14px;
  }

  .content div.btn {
    width: 150px;
    height: 40px;
    line-height: 40px;
    text-align: center;
    background: #31A4FF;
    color: #fff;
    font-size: 16px;
    margin: 15px auto 40px;
  }

  .content span {
    color: #666;
    font-size: 14px;
  }

  /* 竖屏情况下 */
  @media screen and (orientation:portrait) {
    .signBox {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      width: 100%;
      background: #fff;
      z-index: 10000;


    }

    .canvass {
      padding: 20px 15px;
      width: 100%;
      height: 90%;
      box-sizing: border-box;
    }

    canvas {
      width: 100%;
      height: 100%;
      border: 1px dashed #333;
      border-radius: 8px;
    }

    .footer {
      text-align: center;
      height: 10%;
      padding: 10px 0;
      writing-mode: vertical-lr;
      box-sizing: border-box;

    }

    .footer span {
      border: 1px solid #999;
      color: #999;
      height: 30vw;
      width: 40px;
      display: inline-block;
      line-height: 40px;
      font-size: 16px;
      text-align: center;
      background: #fff;
      margin-top: -40px;
      margin-left: 24vw;
      transform: rotate(90deg)
    }

    .footer span:last-child {
      background: #ccc;
      color: #fff;
      border-color: transparent;
      margin-left: 34vw;
    }

    .footer span.active {
      background: #31A4FF;
      color: #fff;
    }
  }

  /* 横屏情况下 */
  @media screen and (orientation:landscape) {
    .signBox {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      width: 100%;
      background: #fff;
      z-index: 10000;

    }

    .canvass {
      float: left;
      padding: 12px 10px;
      width: 90%;
      height: 100%;
      box-sizing: border-box;
    }

    canvas {
      width: 100%;
      height: 100%;
      border: 1px dashed #333;
      border-radius: 5px;
    }

    .footer {
      text-align: center;
      float: right;
      width: 10%;
      height: 100%;
      padding: 0 5px;
      box-sizing: border-box;
      writing-mode: vertical-lr;

    }

    .footer span {
      border: 1px solid #999;
      color: #999;
      width: 22px;
      height: 30vh;
      display: inline-block;
      line-height: 22px;
      font-size: 8px;
      text-align: center;
      background: #fff;
      margin-top: calc (13vh - 20px);
    }

    .footer span:last-child {
      background: #ccc;
      color: #fff;
      border-color: transparent;
      margin-top: 14vh;
    }

    .footer span.active {
      background: #31A4FF;
      color: #fff;
    }
  }

  .take-photo {
    margin: auto;
  }

  .take-photo #submit {
    background: #31A4FF;
    color: #fff;
    font-size: 16px;
    text-align: center;
    margin: 15px auto;
    width: 90%;
    height: 100%;
    line-height: 1.5;
  }

  .take-photo #submit2 {
    background: #E0E0E0;
    color: #fff;
    font-size: 16px;
    text-align: center;
    margin: 15px auto;
    width: 90%;
    width: 90%;
    height: 100%;
    line-height: 1.5;
  }

  .mobile-ts {
    color: #4c4c4c;
    font-size: 12px;
    padding: 10px 10px 0px 25px;
    position: relative;
    text-indent: 25px;

  }

  .imgSpan {
    position: absolute;
    left: 25px;
    text-indent: 0;
  }

  .mobile-ts .imgSpan img {
    width: 16px;
    height: 16px;
  }
</style>

 

 

 

 

posted @ 2020-11-23 17:08  早起开拓者  阅读(375)  评论(0编辑  收藏  举报