基于uniapp 实现画板签字

直接上效果图

代码

javascript 复制代码
<template>
  <view class="container">
    <!-- 签名画布 -->
    <view class="canvas-container">
      <canvas 
        canvas-id="signCanvas" 
        class="sign-canvas"
        @touchstart="handleTouchStart"
        @touchmove="handleTouchMove"
        @touchend="handleTouchEnd"
      ></canvas>
    </view>
    
    <!-- 操作按钮 -->
    <view class="button-group">
      <button @click="clearCanvas" class="btn">清除</button>
      <button @click="saveSignature" class="btn">保存签名</button>
    </view>
    
    <!-- 保存的签名预览 -->
    <view class="preview" v-if="imagePath">
      <image :src="imagePath" mode="widthFix"></image>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      ctx: null, // canvas 上下文
      points: [], // 存储绘制点
      isDrawing: false, // 是否正在绘制
      imagePath: '' // 保存的签名图片路径
    }
  },
  onReady() {
    // 初始化canvas上下文
    this.ctx = uni.createCanvasContext('signCanvas', this);
    
    // 设置画笔样式
    this.ctx.setStrokeStyle('#000000');
    this.ctx.setLineWidth(4);
    this.ctx.setLineCap('round');
    this.ctx.setLineJoin('round');
  },
  methods: {
    // 触摸开始
    handleTouchStart(e) {
      this.isDrawing = true;
      const startX = e.touches[0].x;
      const startY = e.touches[0].y;
      
      this.points = [{x: startX, y: startY}];
      
      // 开始新路径
      this.ctx.beginPath();
      this.ctx.moveTo(startX, startY);
    },
    
    // 触摸移动
    handleTouchMove(e) {
      if (!this.isDrawing) return;
      
      const moveX = e.touches[0].x;
      const moveY = e.touches[0].y;
      
      this.points.push({x: moveX, y: moveY});
      
      // 只保留最近的两个点用于绘制线段
      if (this.points.length > 2) {
        const lastTwoPoints = this.points.slice(-2);
        this.ctx.moveTo(lastTwoPoints[0].x, lastTwoPoints[0].y);
        this.ctx.lineTo(lastTwoPoints[1].x, lastTwoPoints[1].y);
        this.ctx.stroke();
        this.ctx.draw(true);
      }
    },
    
    // 触摸结束
    handleTouchEnd() {
      if (this.points.length < 2) {
        // 如果只有一个点,画一个点
        const point = this.points[0];
        this.ctx.arc(point.x, point.y, 2, 0, 2 * Math.PI);
        this.ctx.fill();
        this.ctx.draw(true);
      }
      
      this.isDrawing = false;
      this.points = [];
    },
    
    // 清除画布
    clearCanvas() {
      this.ctx.clearRect(0, 0, 10000, 10000);
      this.ctx.draw(true);
      this.imagePath = '';
    },
    
    // 保存签名
    saveSignature() {
      uni.canvasToTempFilePath({
        canvasId: 'signCanvas',
        success: (res) => {
          this.imagePath = res.tempFilePath;
          uni.showToast({
            title: '签名保存成功',
            icon: 'success'
          });
          
          // 这里可以添加将签名上传服务器的代码
          // this.uploadSignature(res.tempFilePath);
        },
        fail: (err) => {
          console.error('保存签名失败:', err);
          uni.showToast({
            title: '保存签名失败',
            icon: 'none'
          });
        }
      }, this);
    },
    
    // 上传签名到服务器(可选)
    uploadSignature(tempFilePath) {
      uni.uploadFile({
        url: '你的上传接口地址',
        filePath: tempFilePath,
        name: 'signature',
        success: (uploadRes) => {
          console.log('上传成功', uploadRes);
        },
        fail: (uploadErr) => {
          console.error('上传失败', uploadErr);
        }
      });
    }
  }
}
</script>

<style lang="scss" scoped>
.sign-canvas{
	width: 100vw;
	height: 70vh;
}
</style>
相关推荐
前端大卫5 分钟前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘21 分钟前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare22 分钟前
浅浅看一下设计模式
前端
Lee川26 分钟前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix1 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人1 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl1 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人1 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼1 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端