Vue Canvas 实现签字版


使用Vue、Canvas、ElementUI实现的电子签字版,PC和移动端皆可用。效果如下:

 HTML

<template>
  <section class="signature">
    <div class="signatureBox">
      <div class="canvasBox" ref="canvasHW">
        <canvas ref="canvasF"
                @touchstart='touchStart'
                @touchmove='touchMove'
                @touchend='touchEnd'
                @mousedown="mouseDown"
                @mousemove="mouseMove"
                @mouseup="mouseUp"></canvas>
        <p style="margin:0 0 10px;line-height:20px;color:#999;">注:重写后请重新上传签名</p>
        <div class="btnBox">
          <el-button size="small" type="primary" @click="overwrite">重写</el-button>
          <el-button size="small" type="primary" @click="commit">上传并预览</el-button>
        </div>
      </div>
    </div>
    <img class="imgCanvas" :src="imgUrl">
  </section>
</template>

JS

<script>
export default {
  data () {
    return {
      stageInfo: '',
      imgUrl: '',
      client: {},
      points: [],
      canvasTxt: null,
      startX: 0,
      startY: 0,
      moveY: 0,
      moveX: 0,
      endY: 0,
      endX: 0,
      w: null,
      h: null,
      isDown: false,
      isViewAutograph: this.$route.query.isViews > 0,
      contractSuccess: this.$route.query.contractSuccess
    }
  },
  mounted () {
    // 找到 <canvas> 元素
    let canvas = this.$refs.canvasF
    canvas.height = this.$refs.canvasHW.offsetHeight - 87
    canvas.width = this.$refs.canvasHW.offsetWidth - 2
    // 创建 context 对象
    this.canvasTxt = canvas.getContext('2d')
    this.stageInfo = canvas.getBoundingClientRect()
  },
  methods: {
    //mobile
    touchStart (ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length == 1) {
        let obj = {
          x: ev.targetTouches[0].clienX,
          y: ev.targetTouches[0].clientY,
        }
        this.startX = obj.x
        this.startY = obj.y
        this.canvasTxt.beginPath()
        this.canvasTxt.moveTo(this.startX, this.startY)
        this.canvasTxt.lineTo(obj.x, obj.y)
        this.canvasTxt.stroke()
        this.canvasTxt.closePath()
        this.points.push(obj)
      }
    },
    touchMove (ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length == 1) {
        let obj = {
          x: ev.targetTouches[0].clientX - this.stageInfo.left,
          y: ev.targetTouches[0].clientY - this.stageInfo.top
        }
        this.moveY = obj.y
        this.moveX = obj.x
        this.canvasTxt.beginPath()
        this.canvasTxt.moveTo(this.startX, this.startY)
        this.canvasTxt.lineTo(obj.x, obj.y)
        this.canvasTxt.stroke()
        this.canvasTxt.closePath()
        this.startY = obj.y
        this.startX = obj.x
        this.points.push(obj)
      }
    },
    touchEnd (ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length == 1) {
        let obj = {
          x: ev.targetTouches[0].clientX - this.stageInfo.left,
          y: ev.targetTouches[0].clientY - this.stageInfo.top
        }
        this.canvasTxt.beginPath()
        this.canvasTxt.moveTo(this.startX, this.startY)
        this.canvasTxt.lineTo(obj.x, obj.y)
        this.canvasTxt.stroke()
        this.canvasTxt.closePath()
        this.points.push(obj)
      }
    },
    //pc
    mouseDown (ev) {
      ev = ev || event
      ev.preventDefault()
      if (1) {
        // 鼠标相对于事件源元素(srcElement)的X,Y坐标
        let obj = {
          x: ev.offsetX,
          y: ev.offsetY
        }
        this.startX = obj.x
        this.startY = obj.y
        // 起始一条路径,或重置当前路径
        this.canvasTxt.beginPath()
        // 把路径移动到画布中的指定点,不创建线条
        this.canvasTxt.moveTo(this.startX, this.startY)
        // 添加一个新点,然后在画布中创建从该点到最后指定点的线条
        this.canvasTxt.lineTo(obj.x, obj.y)
        // 绘制已定义的路径
        this.canvasTxt.stroke()
        // 创建从当前点回到起始点的路径
        this.canvasTxt.closePath()
        this.points.push(obj)
        this.isDown = true
      }
    },
    mouseMove (ev) {
      ev = ev || event
      ev.preventDefault()
      if (this.isDown) {
        let obj = {
          x: ev.offsetX,
          y: ev.offsetY
        }
        this.moveY = obj.y
        this.moveX = obj.x
        this.canvasTxt.beginPath()
        this.canvasTxt.moveTo(this.startX, this.startY)
        this.canvasTxt.lineTo(obj.x, obj.y)
        this.canvasTxt.stroke()
        this.canvasTxt.closePath()
        this.startY = obj.y
        this.startX = obj.x
        this.points.push(obj)
      }
    },
    mouseUp (ev) {
      ev = ev || event
      ev.preventDefault()
      if (1) {
        let obj = {
          x: ev.offsetX,
          y: ev.offsetY
        }
        this.canvasTxt.beginPath()
        this.canvasTxt.moveTo(this.startX, this.startY)
        this.canvasTxt.lineTo(obj.x, obj.y)
        this.canvasTxt.stroke()
        this.canvasTxt.closePath()
        this.points.push(obj)
        this.points.push({ x: -1, y: -1 })
        this.isDown = false
      }
    },
    //重写
    overwrite () {
      this.canvasTxt.clearRect(0, 0, this.$refs.canvasF.width, this.$refs.canvasF.height)
      this.points = []
      this.imgUrl = ""
    },
    //提交签名
    commit () {
      this.imgUrl = this.$refs.canvasF.toDataURL();
    }
  }
}
</script>

CSS

<style scoped>
.signatureBox {
  width: 100%;
  height: calc(100% - 50px);
  box-sizing: border-box;
  overflow: hidden;
  background: #fff;
  z-index: 100;
  display: flex;
  flex-direction: column;
}
.canvasBox {
  box-sizing: border-box;
  flex: 1;
}
canvas {
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  box-sizing: border-box;
}
</style>

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM