一个canvas签名组件 vant框架

不多说,直接上代码(vant只是一个遮罩,自己看情况)

https://github.com/toKnowMore/sign-canvas

<template>
  <div class="sign-canvas">
    <van-overlay :show="show" @click="hideCanvas">
      <div class="wrapper" @click.stop>
        <div ref="canvasHw" class="overlay-content">
          <div class="overlay-title">请签名</div>
          <canvas
            ref="canvas"
            canvas-id="signCanvas"
            @touchstart="touchStart"
            @touchmove="touchMove"
            @touchend="touchEnd"
            @mousedown="mouseDown"
            @mousemove="mouseMove"
            @mouseup="mouseUp"/>
          <div class="contents-buttons">
            <div v-show="isCheat !== 1" class="contents-button" @click="cancleSign">取消</div>
            <div v-show="isCheat !== 1" class="contents-button" @click="clearCanvas">清除</div>
            <div class="contents-button" @click="saveCanvas">确定</div>
          </div>
        </div>
      </div>
    </van-overlay>
  </div>
</template>

<script>
var canvas = null
var canvasTxt = null
var points = []
export default {
  name: 'SignCanvas',
  props: {
    show: {
      type: Boolean,
      default: false
    },
    isCheat: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      client: {},
      startX: 0,
      startY: 0,
      moveY: 0,
      moveX: 0,
      isDown: false
    }
  },
  mounted() {
    this.initCanvas()
  },
  methods: {
    hideCanvas() {
      if (this.isCheat === 1) {
        return
      } else {
        this.show = false
      }
    },
    initCanvas() {
      canvas = this.$refs.canvas// 指定canvas
      canvas.width = window.screen.availWidth - 80
      canvas.height = 300
      canvasTxt = canvas.getContext('2d')// 设置2D渲染区域
      canvasTxt.lineWidth = 3 // 设置线的宽度
      canvasTxt.lineCap = 'round'
      canvasTxt.lineJoin = 'round'
    },
    // mobile
    touchStart(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        this.startX = obj.x
        this.startY = obj.y
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.closePath()
        canvasTxt.stroke()
        points.push(obj)
      }
    },
    touchMove(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        this.startX = obj.x
        this.startY = obj.y
        points.push(obj)
      }
    },
    touchEnd(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        points.push(obj)
      }
    },
    // pc
    mouseDown(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        this.startX = obj.x
        this.startY = obj.y
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        points.push(obj)
        this.isDown = true
      }
    },
    mouseMove(ev) {
      ev = ev || event
      ev.preventDefault()
      if (this.isDown) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        this.startY = obj.y
        this.startX = obj.x
        points.push(obj)
      }
    },
    mouseUp(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        points.push(obj)
        points.push({ x: -1, y: -1 })
        this.isDown = false
      }
    },
    cancleSign() {
      this.clearCanvas()
      this.$emit('cancle')
    },
    // 重写
    clearCanvas() {
      canvasTxt.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
      points = []
      this.$emit('clear')
    },
    // 确定签名
    async saveCanvas() {
      const file = {}
      file.type = 'image/png'
      file.name = 'sign.png'
      file.content = this.$refs.canvas.toDataURL()
      const imgFile = await this.dataURLToBlob(file)
      this.$emit('save', imgFile)
    },
    dataURLToBlob(file) {
      var arr = file.content.split(',')
      const bstr = atob(arr[1])
      let n = bstr.length
      const u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new File([u8arr], file.name, {
        type: file.type
      })
    }
  }
}
</script>

<style scoped lang="scss">
.wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 0 40px;
}

.overlay-content {
  border: 1px solid #ededed;
  background-color: white;
  border-radius: 20px;
  width: 100%;
  .contents-signCanvas {
    width: 100%;
    height: 200px;
  }
  .overlay-title {
    text-align: center;
    font-size: 16px;
    padding: 10px 0;
    font-weight: bold;
    border-bottom: 1px solid #ededed;
  }
  .contents-buttons {
    display: flex;
    justify-content: space-between;
    padding: 5px 0;
    border-top: 1px solid #ededed;
    .contents-button {
      padding: 10px 0;
      text-align: center;
      flex: 1;
      font-size: 15px;
      color: rgba(37, 127, 255, 1);
    }
  }
}
</style>

引用

import signCanvas from '@/components/signCanvas'
export default {
  components: {
    modalNumbers,
    signCanvas
  },
  filters: {
    isPass: function(val) {
      switch (val) {
        case 0:
          return '通过'
        case 1:
          return '未通过'
        default:
          break
      }
    },
    questionType(val) {
      switch (val) {
        case 0:
          return '单选题'
        case 1:
          return '多选题'
        case 2:
          return '是非题'
        default:
          break
      }
    }
  },
  data() {
    return {
    	showCanvas: false,
    }
  },
  created(e) {},
  mounted() {},
  methods: {
    cancleCanvas() {
      this.showCanvas = false
      console.log('取消画布')
    },

    clearCanvas() {
      console.log('清除画布')
    },

    saveCanvas(file) {
      this.$toast.loading()
      var formData = new FormData()
      formData.append('file', file)
      uploadFile(formData).then(response => {
        this.$toast.clear()
        this.$set(this.submitExamEdit, 'signImg', response.data)
        this.showCanvas = false
        this.sendSubmitData()
      }).catch(() => {
        this.$toast.clear()
      })
    }
  }
}
</script>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值