vue+canvas实现手写签字

技术 : vue + element + canvas

实现效果

在这里插入图片描述

<template>
  <ElDialog
    :visible.sync="modal"
    :close-on-click-modal="false"
    title="确认金额"
    width="640px"
  >
    <div v-if="modal" class="wrapper">
      <div class="handCenter">
        <h2 class="h2">
          请在如下方框区域书写您的姓名
        </h2>
        <canvas id="handWriting" :width="canvasWidth" :height="canvasHeight">浏览器不支持canvas<!-- 如果不支持会显示这段文字 --></canvas>
      </div>
    </div>
    <Spin v-if="loading" size="large" fix />
    <div slot="footer">
      <ElButton class="delBtn" type="info" @click="retDraw">
        重写
      </ElButton>
      <ElButton class="subBtn" type="primary" @click="uploadCanvasImg">
        提交
      </ElButton>
    </div>
  </ElDialog>
</template>
<script>

export default {
  components: {
    //组成局部组件
  },
  data() {
    return {
      id: '',
      loading: false,
      modal: false,
      files: [],
      attachedNum: 0,


      canvasName: 'handWriting',
      ctx: '',
      canvasWidth: 600,
      canvasHeight: 280,
      lineColor: '#1A1A1A', // 颜色


      penWidth: 6,
      penClick: false,
      startAxisX: 0,
      startAxisY: 0,
      brackGroudColor: '#ffffff',


    }
  },

  methods: {
    // 函数
    open(val) {
      this.id = val
      this.modal = true
      this.$nextTick(() => {
        this.init()

      })

    },

    success() {
      this.modal = false
      this.loading = false
      this.$emit('success')
    },


    /*======所有自定义函数======*/
    init() {
      let canvas = document.getElementById('handWriting') //获取canvas标签

      const ctx = canvas.getContext('2d')

      this.ctx = ctx

      this.setCanvasBg()

      /* 将canvas背景设置为 白底,不设置  导出的canvas的背景为透明 */
      canvas.addEventListener('mousemove', this.drawing) //鼠标移动事件
      canvas.addEventListener('mousedown', this.penDown) //鼠标按下事件
      canvas.addEventListener('mouseup', this.penUp) //鼠标弹起事件
      canvas.addEventListener('mouseleave', this.penUp) //鼠标离开目标区域  防止快速移动, 鼠标离开目标区域且松开 ,但是仍然绘画的情景

    },

    // 笔迹移动
    drawing(event) {
      event.stopPropagation()
      event.preventDefault()
      if (!this.penClick) return
      const canvas = document.getElementById('handWriting') //获取canvas标签
      const ctx = canvas.getContext('2d')//创建 contextconst canvas = document.getElementById('canvas');  对象
      const stopAxisX = event.pageX
      const stopAxisY = event.pageY
      ctx.beginPath()
      const cl = canvas.getBoundingClientRect().left
      const ct = canvas.getBoundingClientRect().top
      ctx.moveTo(this.startAxisX - cl, this.startAxisY - ct)//moveTo(x,y) 定义线条开始坐标
      ctx.lineTo(stopAxisX - cl, stopAxisY - ct)//lineTo(x,y) 定义线条结束坐标
      ctx.strokeStyle = this.lineColor
      ctx.lineWidth = this.penWidth
      ctx.lineCap = 'round'
      ctx.stroke()// stroke() 方法来绘制线条
      this.startAxisX = stopAxisX
      this.startAxisY = stopAxisY
    },
    penDown(event) {
      event.stopPropagation()
      event.preventDefault()
      this.penClick = true
      this.startAxisX = event.pageX
      this.startAxisY = event.pageY
    },
    penUp(e) {
      this.penClick = false
      e.stopPropagation()
      e.preventDefault()


    },

    //清空
    retDraw() {
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      this.setCanvasBg()
    },


    //判断canvas中是否有内容 新建一个空白的画布 大小背景色都相同
    isCanvasBlank(canvas) {
      var blank = document.createElement('canvas')
      blank.width = canvas.width
      blank.height = canvas.height
      const ctx = blank.getContext('2d')
      ctx.fillStyle = this.brackGroudColor
      ctx.fillRect(0, 0, blank.width, blank.height)

      return canvas.toDataURL() == blank.toDataURL()
    },

    //上传
    async uploadCanvasImg() {
      const flag = this.isCanvasBlank(document.getElementById('handWriting'))
      if (flag) {
        return this.$Http.msg.warning({ title: '警告', desc: '请在画板区域签名!' })

      }
      const canvas = document.getElementById('handWriting') //获取canvas标签
      // canvas转为blob并上传,但是浏览器有兼容问题  新版chrome和firefox中能正常使用  其他浏览器报错
      //  这里采用使用toDataURL()将file转成base64编码,然后转成blob

      const dataURL = canvas.toDataURL()
      const blob = this.base64ToBlob(dataURL)
      const formData = new FormData()
      // 图片ajax上传,字段名是file
      formData.append('file', blob)
      formData.append('fileUploadSource', 'CONFIRM_IMAGE')
      try {
        this.loading = true
        //  开始上传 获得线上url路径

        const res = await this.$Http.postFile('xxxxxx', formData, null, )

        const param = {
          confirmImage: res.data,
          id: this.id,
        }
        const { code, data } = await this.$Http.postForm('xddddddd', param)
        if (code == 0 && data) {//特殊场景 
          this.$Http.msg.warning({ title: '提示', desc: data })
        }
        this.success()
      } catch (err) {

        this.loading = false
        this.$Http.msg.warning({ title: '提示', desc: err.message })

      }

    },

    base64ToBlob(dataurl) {
      var arr = dataurl.split(',')//分割为数组,分割到第一个逗号
      let mime = arr[0].match(/:(.*?);/)[1]//获取分割后的base64前缀中的类型
      let bstr = window.atob(arr[1])
      let n = bstr.length
      let u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new Blob([u8arr], { type: mime })

    },
    //设置canvas背景色  不设置  导出的canvas的背景为透明
    //@params:字符串  color
    setCanvasBg() {
      /* 将canvas背景设置为 白底,不设置  导出的canvas的背景为透明 */
      //rect() 参数说明  矩形路径左上角的横坐标,左上角的纵坐标, 矩形路径的宽度, 矩形路径的高度
      //这里是 canvasHeight - 4 是因为下边盖住边框了,所以手动减了写
      this.ctx.fillStyle = this.brackGroudColor
      this.ctx.strokeStyle = this.lineColor
      this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight)


    },
  },
}
</script>
<style scoped>
  #handWriting{
    border: 2px dashed #ddd;
    box-sizing: content-box;
  }
  .h2{
    text-align: center;
      margin-bottom: 10px;
  }
</style>

借鉴网址: https://blog.csdn.net/Twinkle_sone/article/details/121476250

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值