使用 uni-app + vue3 实现手写签名(拿来即用)

154 阅读1分钟

背景:最近在做一款俄语学习的微信小程序(跨端),由于俄语的特殊性同时方便用户在移动端练习书写俄语,开发了一个手写板的小功能(即签字班功能)。主要是实现方式是利用canvas绘制能力。

展示效果:

Snipaste_2025-02-19_20-26-02.jpg

上代码


<template>
  <view class="signature-container">
    <canvas
      ref="signatureCanvas"
      canvas-id="signatureCanvas"
      style="width: 100%; height: 300px"
      @touchstart="startDrawing"
      @touchmove="draw"
      @touchend="endDrawing"
      @touchcancel="endDrawing"
    ></canvas>
    <button @click="clearSignature">清空</button>
    <button @click="saveSignature">保存</button>
  </view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { onReady } from '@dcloudio/uni-app'

const signatureCanvas = ref(null)
let ctx = null
let isDrawing = false
let lastX = 0
let lastY = 0

// 禁用下拉刷新和上拉加载
onReady(() => {
  uni.stopPullDownRefresh() // 禁用下拉刷新
})

onMounted(() => {
  // 获取 canvas 上下文
  ctx = uni.createCanvasContext('signatureCanvas')
})

// 开始绘制
const startDrawing = (e) => {
  isDrawing = true
  const touch = e.touches[0]
  lastX = touch.x
  lastY = touch.y
}

// 绘制签名
const draw = (e) => {
  if (!isDrawing) return

  const touch = e.touches[0]
  const currentX = touch.x
  const currentY = touch.y

  // 绘制线条
  ctx.beginPath()
  ctx.moveTo(lastX, lastY)
  ctx.lineTo(currentX, currentY)
  ctx.strokeStyle = '#000' // 设置绘制颜色
  ctx.lineWidth = 2 // 设置线宽
  ctx.lineCap = 'round' // 设置圆角连接
  ctx.lineJoin = 'round' // 设置圆角连接
  ctx.stroke()
  ctx.closePath()

  lastX = currentX // 更新上一个点坐标
  lastY = currentY

  ctx.draw(true) // 确保更新 canvas 内容
}

// 结束绘制
const endDrawing = () => {
  isDrawing = false
}

// 清空签名
const clearSignature = () => {
  ctx.clearRect(0, 0, 300, 300) // 清除签名区域
  ctx.draw(true)
}

// 保存签名
const saveSignature = () => {
  // 将 canvas 转为图片 (base64)
  uni.canvasToTempFilePath({
    canvasId: 'signatureCanvas',
    success(res) {
      console.log('签名图片:', res.tempFilePath)
      // 可以上传图片或者保存
    },
    fail(err) {
      console.log('保存失败', err)
    },
  })
}
</script>

<style scoped>
.signature-container {
  padding: 20rpx;
  text-align: center;
}
</style>