前端实现电子签名

具体细节就不一一说了,这篇也是学习于:前端实现电子签名(web、移动端)通用

大家感兴趣可以去看看,是通过原生canvas实现,我这篇是对其进行了改造,并用在vue项目中,并且增加了浏览器改变画板可以达到一个自适应,签名完成之后,可以拿到图片的blob对象、以及base64编码等,根据需求适当选择,直接上代码吧:

我将 签名画板单独封装为一个组件,在需要的地方引入即可,注意要给外层容器一个宽高,该组件默认为宽高都为100%

<template>
  <div style="width: 100%;height: 100%;">
    <div class="drawing-board">
      <canvas id="canvas"></canvas>
    </div>
    <div class="tool-bar">
      <el-button @click="reset()" size="small" type="primary">清除</el-button>
      <el-button @click="save()" size="small" type="success">确定</el-button>
    </div>
  </div>
</template>
<script>
const $ = name => document.querySelector(name)
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent)) // 判断是否为移动端
// 配置内容
const config = {
  width: 0, // 宽度
  height: 0, // 高度
  lineWidth: 5, // 线宽
  strokeStyle: 'red', // 线条颜色
  lineCap: 'round', // 设置线条两端圆角
  lineJoin: 'round', // 线条交汇处圆角
}
// 偏移量
const client = {
  offsetX: 0,
  offsetY: 0
}
let canvas,ctx;
export default {
  mounted(){
    this.drawingBoardInit()
  },
  destroyed() {
    window.removeEventListener(mobileStatus ? "touchstart" : "mousedown", this.init)
    window.removeEventListener(mobileStatus ? "touchend" : "mouseup", this.cloaseDraw)
    window.removeEventListener('resize', this.resetSize)
  },
  methods:{
    drawingBoardInit() {
      const { width, height, left, top } = $('.drawing-board').getBoundingClientRect()
      config.width = width
      config.height = height
      client.offsetX = left
      client.offsetY = top
      // canvas 实例
      canvas = $('#canvas')
      // 设置宽高
      canvas.width = config.width
      canvas.height = config.height
      // 设置边框
      canvas.style.border = '1px solid #000'
      // 创建上下文
      ctx = canvas.getContext('2d')
      // 设置填充背景色
      ctx.fillStyle = 'transparent'
      // 绘制填充矩形
      ctx.fillRect(
        0, // x 轴起始绘制位置
        0, // y 轴起始绘制位置
        config.width, // 宽度
        config.height // 高度
      );
      // 创建鼠标/手势按下监听器
      window.addEventListener(mobileStatus ? "touchstart" : "mousedown", this.init)
      // 创建鼠标/手势 弹起/离开 监听器
      window.addEventListener(mobileStatus ? "touchend" : "mouseup", this.cloaseDraw)
      // 自适应画布
      window.addEventListener('resize', this.resetSize)
    },
    // 鼠标按下
    init(event) {
      // 获取偏移量及坐标
      const { clientX, clientY } = mobileStatus ? event.changedTouches[0] : event
      // 清除以上一次 beginPath 之后的所有路径,进行绘制
      ctx.beginPath()
      // 根据配置文件设置相应配置
      ctx.lineWidth = config.lineWidth
      ctx.strokeStyle = config.strokeStyle
      ctx.lineCap = config.lineCap
      ctx.lineJoin = config.lineJoin
      // 设置画线起始点位(减去 左边、上方的偏移量很关键)
      ctx.moveTo(clientX - client.offsetX, clientY - client.offsetY)
      // 监听 鼠标移动或手势移动
      window.addEventListener(mobileStatus ? "touchmove" : "mousemove", this.draw)
    },
    // 绘制
    draw(event) {
      // 获取当前坐标点位
      const { clientX, clientY } = mobileStatus ? event.changedTouches[0] : event
      // 根据坐标点位移动添加线条(减去 左边、上方的偏移量很关键)
      ctx.lineTo(clientX - client.offsetX, clientY - client.offsetY)
      // 绘制
      ctx.stroke()
    },
    // 结束绘制
    cloaseDraw() {
      // 结束绘制
      ctx.closePath()
      // 移除鼠标移动或手势移动监听器
      window.removeEventListener("mousemove", this.draw)
    },
    // 清除
    reset() {
      // 清空当前画布上的所有绘制内容
      ctx.clearRect(0, 0, config.width, config.height)
    },
    // 将画布内容保存为图片
    save() {
      // 将画布内容转为base64编码
      let imgBase64 = canvas.toDataURL('png')
      console.log(imgBase64, 'imgBase64-->>') // base64编码
      // 将canvas上的内容转成blob流
      canvas.toBlob(blob => {
        console.log(blob, 'blob-->>') // 文件二进制流
        // 获取当前时间,用来当做文件名
        const date = new Date().getTime()
        // 创建一个 a 标签
        const link = document.createElement('a')
        // 设置 a 标签的下载文件名
        link.download = `${date}.png`
        // 设置 a 标签的跳转路径为 文件流地址
        link.href = URL.createObjectURL(blob)
        // 手动触发 a 标签的点击事件
        link.click()
        // 移除 a 标签
        link.remove()
      })
    },
    // 浏览器分辨率改变 自适应重置
    resetSize() {
      const { width, height, left, top } = $('.drawing-board').getBoundingClientRect()
      const dx = Math.abs(left - client.offsetX)
      const dy = Math.abs(top - client.offsetY)
      // 浏览器分辨率改变 重新设置配置项
      config.width = width
      config.height = height
      client.offsetX = left
      client.offsetY = top
      // 重置canvas宽高 会导致 之前canvas的内容丢失,得先存一份,重置完宽高,再绘制上去
      const canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height)
      // 重置 canvas 宽高
      canvas.width = width
      canvas.height = height
      // 改变完宽高 重绘画布
      ctx.putImageData(canvasData, dx, dy)
    }
  }
}
</script>
<style scoped>
.drawing-board {
  width: 100%;
  height: calc(100% - 40px);
  border-bottom: 1px solid #ccc;
  box-sizing: border-box;
}
.tool-bar {
  width: 100%;
  height: 40px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
</style>

猜你喜欢

转载自blog.csdn.net/m0_51431448/article/details/128354207