当前位置:首页 > VUE

vue 实现电子签名

2026-01-18 21:20:44VUE

实现电子签名的基本思路

在Vue中实现电子签名功能,主要涉及以下几个关键点:使用HTML5 Canvas绘制签名、保存签名数据、清除签名以及响应式调整画布大小。

安装依赖(可选)

如果项目需要更复杂的签名处理,可以安装signature_pad库:

npm install signature_pad

基础实现代码示例

<template>
  <div class="signature-container">
    <canvas 
      ref="canvas"
      @mousedown="startDrawing"
      @mousemove="draw"
      @mouseup="stopDrawing"
      @mouseleave="stopDrawing"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
    ></canvas>
    <div class="controls">
      <button @click="clearSignature">清除</button>
      <button @click="saveSignature">保存</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isDrawing: false,
      lastX: 0,
      lastY: 0,
      canvas: null,
      ctx: null
    }
  },
  mounted() {
    this.initCanvas()
    window.addEventListener('resize', this.handleResize)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize)
  },
  methods: {
    initCanvas() {
      this.canvas = this.$refs.canvas
      this.ctx = this.canvas.getContext('2d')
      this.resizeCanvas()

      // 设置绘制样式
      this.ctx.strokeStyle = '#000'
      this.ctx.lineWidth = 2
      this.ctx.lineCap = 'round'
      this.ctx.lineJoin = 'round'
    },
    resizeCanvas() {
      const parent = this.canvas.parentElement
      this.canvas.width = parent.offsetWidth
      this.canvas.height = parent.offsetHeight * 0.8
    },
    handleResize() {
      this.resizeCanvas()
    },
    startDrawing(e) {
      this.isDrawing = true
      const pos = this.getPosition(e)
      this.lastX = pos.x
      this.lastY = pos.y
    },
    draw(e) {
      if (!this.isDrawing) return

      const pos = this.getPosition(e)
      this.ctx.beginPath()
      this.ctx.moveTo(this.lastX, this.lastY)
      this.ctx.lineTo(pos.x, pos.y)
      this.ctx.stroke()

      this.lastX = pos.x
      this.lastY = pos.y
    },
    stopDrawing() {
      this.isDrawing = false
    },
    getPosition(e) {
      const rect = this.canvas.getBoundingClientRect()
      let x, y

      if (e.type.includes('touch')) {
        x = e.touches[0].clientX - rect.left
        y = e.touches[0].clientY - rect.top
      } else {
        x = e.clientX - rect.left
        y = e.clientY - rect.top
      }

      return { x, y }
    },
    clearSignature() {
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
    },
    saveSignature() {
      const dataURL = this.canvas.toDataURL('image/png')
      // 可以发送到服务器或保存到本地
      console.log(dataURL)
      this.$emit('signature-saved', dataURL)
    },
    handleTouchStart(e) {
      e.preventDefault()
      this.startDrawing(e)
    },
    handleTouchMove(e) {
      e.preventDefault()
      this.draw(e)
    },
    handleTouchEnd(e) {
      e.preventDefault()
      this.stopDrawing()
    }
  }
}
</script>

<style scoped>
.signature-container {
  width: 100%;
  height: 100%;
}
canvas {
  border: 1px solid #ddd;
  background-color: white;
}
.controls {
  margin-top: 10px;
}
button {
  margin-right: 10px;
}
</style>

使用signature_pad库的优化方案

<template>
  <div>
    <canvas ref="canvas"></canvas>
    <button @click="clear">清除</button>
    <button @click="save">保存</button>
  </div>
</template>

<script>
import SignaturePad from 'signature_pad'

export default {
  data() {
    return {
      signaturePad: null
    }
  },
  mounted() {
    this.signaturePad = new SignaturePad(this.$refs.canvas, {
      minWidth: 1,
      maxWidth: 3,
      penColor: 'black'
    })
    this.resizeCanvas()
    window.addEventListener('resize', this.resizeCanvas)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.resizeCanvas)
  },
  methods: {
    resizeCanvas() {
      const canvas = this.$refs.canvas
      const ratio = Math.max(window.devicePixelRatio || 1, 1)
      canvas.width = canvas.offsetWidth * ratio
      canvas.height = canvas.offsetHeight * ratio
      canvas.getContext('2d').scale(ratio, ratio)
      this.signaturePad.clear() // 防止缩放后签名模糊
    },
    clear() {
      this.signaturePad.clear()
    },
    save() {
      if (this.signaturePad.isEmpty()) {
        alert('请先签名')
        return
      }
      const data = this.signaturePad.toDataURL()
      this.$emit('save', data)
    }
  }
}
</script>

实现要点说明

画布初始化 确保画布大小适应容器,并设置好绘制样式。对于高DPI屏幕,需要考虑像素比例。

vue 实现电子签名

触摸支持 通过添加触摸事件处理程序,使签名功能在移动设备上也能正常工作。

数据保存 使用Canvas的toDataURL方法将签名转换为Base64格式的图片数据,便于存储或上传。

vue 实现电子签名

响应式处理 监听窗口大小变化事件,动态调整画布尺寸,保证签名区域始终适合当前视图。

样式优化 添加适当的边框和背景色,使签名区域清晰可见。控制按钮提供基本的交互功能。

进阶功能建议

  • 添加签名验证功能,检测签名是否为空
  • 实现撤销上一步操作的功能
  • 支持多种笔触颜色和粗细选择
  • 添加时间戳等元数据到签名图片
  • 集成后端API实现签名存储和验证

标签: 电子签名vue
分享给朋友:

相关文章

js实现vue

js实现vue

Vue.js 的基本实现方法 在 JavaScript 中实现 Vue.js 的功能,可以通过直接引入 Vue 库或使用现代构建工具(如 Vite 或 Webpack)。以下是几种常见的实现方式:…

vue 实现单选

vue 实现单选

使用 v-model 绑定单选值 在 Vue 中,可以通过 v-model 绑定单选按钮的值。定义一个响应式数据(如 selectedOption),并将其与单选按钮的 value 属性关联。…

vue原理实现

vue原理实现

Vue 原理实现的核心机制 Vue.js 的核心原理基于响应式系统、虚拟 DOM 和模板编译。以下是其核心实现机制的分解: 响应式系统 Vue 使用 Object.defineProperty(Vu…

vue实现popup

vue实现popup

Vue 实现 Popup 弹窗 使用 Vue 原生组件 创建一个基本的 Vue 组件作为弹窗,通过 v-if 或 v-show 控制显示隐藏。 <template> <div&…

vue实现selectable

vue实现selectable

Vue 实现可选择的 Select 组件 在 Vue 中实现一个可选择的 Select 组件,可以通过以下几种方式: 使用原生 HTML select 元素 <template> &…

vue实现增加

vue实现增加

实现 Vue 中的新增功能 在 Vue 中实现新增功能通常涉及数据绑定、表单处理和状态管理。以下是几种常见的实现方式: 数据绑定与列表渲染 通过 v-model 绑定表单输入,使用数组的 push…