基于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>
相关推荐
犹豫的果冻布丁1 分钟前
从零给 DeepSeek Harness 写一个壁纸皮肤插件(已开源)
前端·后端
漏刻有时20 分钟前
数据可视化Three.js 3D 地图实战:单文件原生实现省域区县拉伸建模
前端
会说话的番茄26 分钟前
AI 满嘴跑火车怎么办?给它配个"小抄"
前端·aigc
计算机魔术师27 分钟前
AI 权力集中辩论实录:从「token 工厂」到「唯一幸存者」
前端
eric-sjq33 分钟前
WanlyFrontend 中文声明式前端语言完全指南:让 0.6B 模型写出漂亮网页
前端
Full Stack Developme36 分钟前
跨站请求伪造 (CSRF) 是什么 设计及工作原理
前端·okhttp·csrf
MoSTChillax44 分钟前
UI规范设计:从视觉到交互的全面指南
前端·ui·产品经理·设计规范·vibecoding
雪碧聊技术1 小时前
Vue + Element Plus 实现文本溢出显示省略号及悬浮提示
前端·javascript·css·vue.js·文本溢出省略
eric-sjq1 小时前
0.6B 前端生成模型本地部署实战:消费级显卡跑通 WanlyFrontend 全流程
前端·本地部署
小妖6662 小时前
设置了 box-sizing: border-box; 不管用,下边框还是被挤压没了
前端·css·html