当前位置:首页 > 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 库:

vue实现页面签字

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>

移动端适配方案

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

vue实现页面签字

<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 中实现冒泡排序,可以通过数据绑定和响应式特性动态展示排序过程。以下是一个完整的实现示例,包含代码和详细说明。 数据准备 在 Vue 的 data 中定义一个数组作为…

vue datepicker 实现

vue datepicker 实现

实现 Vue Datepicker 的基本方法 在 Vue 项目中实现日期选择功能,可以使用第三方库如 vue-datepicker 或 v-calendar。以下是两种常见实现方式: 安装 vue…

vue列表实现

vue列表实现

Vue 列表实现方法 使用 v-for 指令 v-for 是 Vue 中用于渲染列表的核心指令,基于数据源动态生成 DOM 元素。语法格式为 item in items 或 (item, index)…

vue实现handsontable

vue实现handsontable

Vue 中实现 Handsontable 要在 Vue 项目中集成 Handsontable,可以使用官方提供的 @handsontable/vue 封装库。以下是一个完整的实现步骤。 安装依赖 确…

vue实现伸缩

vue实现伸缩

Vue实现伸缩功能的方法 使用CSS过渡和Vue的v-if或v-show 通过CSS的transition属性结合Vue的条件渲染指令(v-if或v-show)可以实现元素的伸缩效果。定义一个CSS类…

vue实现文章滚动

vue实现文章滚动

Vue 实现文章滚动效果 使用 CSS 实现基础滚动 通过 CSS 的 overflow 和 height 属性控制滚动区域,适用于静态内容滚动。在 Vue 模板中定义固定高度的容器,内容超出后自动滚…