当前位置:首页 > VUE

vue实现页面签字

2026-02-11 06:37:29VUE

使用 canvas 实现电子签名

在 Vue 中可以通过原生 canvas 或第三方库实现签名功能。以下是一个基于 canvas 的基础实现方案:

<template>
  <div class="signature-container">
    <canvas 
      ref="signaturePad" 
      @mousedown="startDrawing"
      @mousemove="draw"
      @mouseup="stopDrawing"
      @mouseleave="stopDrawing"
      @touchstart="startDrawing"
      @touchmove="draw"
      @touchend="stopDrawing"
    ></canvas>
    <button @click="clearCanvas">清除</button>
    <button @click="saveSignature">保存</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      isDrawing: false,
      lastX: 0,
      lastY: 0,
      canvas: null,
      ctx: null
    }
  },
  mounted() {
    this.initCanvas()
  },
  methods: {
    initCanvas() {
      this.canvas = this.$refs.signaturePad
      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 container = this.canvas.parentElement
      this.canvas.width = container.offsetWidth
      this.canvas.height = container.offsetHeight * 0.7
    },
    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()
      return {
        x: (e.clientX || e.touches[0].clientX) - rect.left,
        y: (e.clientY || e.touches[0].clientY) - rect.top
      }
    },
    clearCanvas() {
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
    },
    saveSignature() {
      const image = this.canvas.toDataURL('image/png')
      this.$emit('signature-saved', image)
    }
  }
}
</script>

使用第三方库 signature_pad

对于更专业的签名需求,推荐使用 signature_pad 库:

npm install signature_pad
<template>
  <div>
    <canvas ref="signatureCanvas"></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.initSignaturePad()
  },
  methods: {
    initSignaturePad() {
      const canvas = this.$refs.signatureCanvas
      canvas.width = canvas.offsetWidth
      canvas.height = canvas.offsetHeight

      this.signaturePad = new SignaturePad(canvas, {
        minWidth: 1,
        maxWidth: 3,
        penColor: '#000',
        backgroundColor: 'rgb(255, 255, 255)'
      })
    },
    clear() {
      this.signaturePad.clear()
    },
    save() {
      if (this.signaturePad.isEmpty()) {
        alert('请先签名')
        return
      }

      const dataURL = this.signaturePad.toDataURL()
      this.$emit('signature-saved', dataURL)
    }
  }
}
</script>

移动端适配方案

为确保在移动设备上的良好体验,需要添加以下样式和配置:

<style scoped>
canvas {
  border: 1px solid #ddd;
  background-color: #fff;
  touch-action: none; /* 禁用浏览器默认手势 */
}

.signature-container {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
}

button {
  margin-top: 10px;
  padding: 8px 16px;
  background: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-right: 10px;
}
</style>

保存签名数据

签名通常需要以图片形式保存或上传:

methods: {
  async uploadSignature() {
    const blob = await this.dataURLToBlob(this.signaturePad.toDataURL())
    const formData = new FormData()
    formData.append('signature', blob, 'signature.png')

    try {
      const response = await axios.post('/api/upload-signature', formData)
      console.log('上传成功', response.data)
    } catch (error) {
      console.error('上传失败', error)
    }
  },
  dataURLToBlob(dataURL) {
    const arr = dataURL.split(',')
    const mime = arr[0].match(/:(.*?);/)[1]
    const bstr = atob(arr[1])
    let n = bstr.length
    const u8arr = new Uint8Array(n)
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }
    return new Blob([u8arr], { type: mime })
  }
}

签名验证功能

添加签名是否为空验证:

methods: {
  validateSignature() {
    if (this.signaturePad.isEmpty()) {
      return {
        valid: false,
        message: '请提供有效签名'
      }
    }
    return {
      valid: true,
      message: ''
    }
  }
}

vue实现页面签字

标签: 页面vue
分享给朋友:

相关文章

订单 vue实现

订单 vue实现

Vue 实现订单功能 数据模型设计 订单功能通常需要设计以下数据结构: // 订单数据结构 const order = { id: '', // 订单ID userId:…

vue实现多级弹窗

vue实现多级弹窗

Vue 多级弹窗实现方法 方法一:使用动态组件与递归组件 在 Vue 中可以通过动态组件配合递归组件实现多级弹窗。定义一个基础弹窗组件,通过递归调用自身实现层级嵌套。 基础弹窗组件模板示例: &…

vue实现页面分模块

vue实现页面分模块

Vue 实现页面分模块的方法 在 Vue 中实现页面分模块可以通过组件化、动态路由、懒加载等方式实现。以下是几种常见的方法: 组件化拆分 将页面拆分为多个独立的组件,每个组件负责一个模块的功能和样…

vue实现多选题

vue实现多选题

Vue实现多选题的方法 使用Vue实现多选题功能,可以通过v-model绑定数组、动态渲染选项、以及处理选中状态来实现。以下是一个完整的实现示例: 基础实现代码 <template>…

vue实现自定义登录

vue实现自定义登录

实现自定义登录的基本步骤 在Vue中实现自定义登录功能通常需要结合前端和后端技术。以下是一个基本的实现流程: 创建登录表单组件 使用Vue的单文件组件创建一个登录表单,包含用户名和密码输入框以及提…

vue实现选中单元格

vue实现选中单元格

Vue 实现选中单元格的方法 基础实现思路 在 Vue 中实现选中单元格功能,通常可以通过动态绑定 class 或 style 来实现。以下是一个基于表格的简单实现示例: <template…