自学内容网 自学内容网

微信小程序做电子签名功能

文章目录


最近需求要做就记录一下。

人狠话不多,直接上功能:
在这里插入图片描述

直接搂代码吧,复制过去就可以用,有其他需求自己改吧改吧。

signature.wxml

<!-- 电子签名页面 -->
<custom-navbar 
  title="电子签名"
  show-home="{{false}}"
/>
<view class="signature-page">
  <!-- 顶部操作栏 -->
  <view class="action-bar">
    <t-button theme="primary" icon="refresh" bind:tap="handleClear">重写</t-button>
    <t-button theme="primary" icon="rollback" bind:tap="handleUndo">撤销</t-button>
    <t-button theme="primary" icon="check" bind:tap="handleSubmit">提交</t-button>
  </view>

  <!-- 签名区域 -->
  <view class="signature-area-large">
    <canvas
      type="2d"
      id="signatureCanvas"
      class="signature-canvas-large"
      disable-scroll="{{true}}"
      bindtouchstart="handleTouchStart"
      bindtouchmove="handleTouchMove"
      bindtouchend="handleTouchEnd"
    ></canvas>
  </view>

  <!-- 提示文本 -->
  <view class="signature-tips">
    请在上方区域书写您的签名
  </view>
</view> 

注意:我是用的tdesign这个UI,所以是t-button


signature.wxss

/* 页面容器 */
.signature-page {
  width: 100vw;
  height: calc(100vh - 44rpx);
  background-color: #f6f6f6;
  display: flex;
  flex-direction: column;
  padding: 16rpx;
  box-sizing: border-box;
}

/* 顶部操作栏 */
.action-bar {
  display: flex;
  justify-content: flex-end;
  gap: 16rpx;
  margin-bottom: 20rpx;
  padding: 0 10rpx;
}

/* 自定义按钮样式 */
.action-bar .t-button {
  min-width: auto;
  padding: 0 16rpx;
  font-size: 18rpx !important;
  height: 35rpx !important;
  line-height: 35rpx !important;
}

/* 按钮图标样式 */
.action-bar .t-icon,
.action-bar .t-button__icon,
.action-bar .t-button .t-icon {
  font-size: 20rpx !important;
}

/* 签名区域-大尺寸 */
.signature-area-large {
  flex: 1;
  background-color: #ffffff;
  border-radius: 16rpx;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  overflow: hidden;
  position: relative;
  margin: 0 auto;
  width: 94vw;
  height: 80vh;
}

/* 签名画布-大尺寸 */
.signature-canvas-large {
  width: 100%;
  height: 100%;
  background-color: #ffffff;
}

/* 提示文本 */
.signature-tips {
  text-align: center;
  color: #999999;
  font-size: 12px;
  margin-top: 16rpx;
}


signature.js

Page({
  data: {
    ctx: null,
    points: [], // 存储所有笔画
    currentStroke: [], // 当前笔画
    isDrawing: false,
  },

  /**
   * 生命周期函数--监听页面加载
   * 初始化画布设置
   */
  onLoad() {
    this.initCanvas();
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    
  },

  /**
   * 初始化画布
   * 设置画布大小、像素比例和画笔样式
   */
  async initCanvas() {
    const query = wx.createSelectorQuery();
    query.select('#signatureCanvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node;
        const ctx = canvas.getContext('2d');

        // 设置画布大小,使用新的API获取设备像素比
        const dpr = wx.getWindowInfo().pixelRatio;
        canvas.width = res[0].width * dpr;
        canvas.height = res[0].height * dpr;
        ctx.scale(dpr, dpr);

        // 设置画笔样式
        ctx.strokeStyle = '#000000';
        ctx.lineWidth = 3;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';

        this.setData({ ctx });
      });
  },

  /**
   * 处理触摸开始事件
   * 开始一个新的笔画,记录起始点
   * @param {Object} e - 触摸事件对象
   */
  handleTouchStart(e) {
    const { x, y } = e.touches[0];
    this.setData({
      isDrawing: true,
      currentStroke: [[x, y]]
    });
    this.data.ctx.beginPath();
    this.data.ctx.moveTo(x, y);
  },

  /**
   * 处理触摸移动事件
   * 继续绘制当前笔画的路径
   * @param {Object} e - 触摸事件对象
   */
  handleTouchMove(e) {
    if (!this.data.isDrawing) return;
    const { x, y } = e.touches[0];
    this.data.currentStroke.push([x, y]);
    this.data.ctx.lineTo(x, y);
    this.data.ctx.stroke();
  },

  /**
   * 处理触摸结束事件
   * 完成当前笔画,将其添加到笔画历史中
   */
  handleTouchEnd() {
    if (!this.data.isDrawing) return;
    this.setData({
      isDrawing: false,
      points: [...this.data.points, this.data.currentStroke],
      currentStroke: []
    });
  },

  /**
   * 清除画布内容
   * 清空所有笔画记录和画布显示
   */
  handleClear() {
    const { ctx } = this.data;
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    this.setData({ points: [] });
  },

  /**
   * 撤销上一步操作
   * 移除最后一笔,并重绘剩余的笔画
   */
  handleUndo() {
    if (this.data.points.length === 0) return;
    
    const { ctx } = this.data;
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    
    // 移除最后一笔
    const newPoints = this.data.points.slice(0, -1);
    this.setData({ points: newPoints });
    
    // 重绘所有笔画
    newPoints.forEach(stroke => {
      ctx.beginPath();
      ctx.moveTo(stroke[0][0], stroke[0][1]);
      stroke.forEach(([x, y]) => {
        ctx.lineTo(x, y);
      });
      ctx.stroke();
    });
  },

  /**
   * 提交签名
   * 将画布内容转换为图片并处理提交逻辑
   * @returns {Promise<void>}
   */
  async handleSubmit() {
    if (this.data.points.length === 0) {
      wx.showToast({
        title: '请先签名',
        icon: 'none'
      });
      return;
    }

// todo: 这里根据具体业务写吧,我这只是举个例子
    try {
      // 将画布内容转换为图片
      const tempFilePath = await new Promise((resolve, reject) => {
        wx.canvasToTempFilePath({
          canvas: this.data.ctx.canvas,
          success: res => resolve(res.tempFilePath),
          fail: reject
        });
      });

      // 这里可以处理签名图片,比如上传到服务器
      console.log('签名图片路径:', tempFilePath);
      
      wx.showToast({
        title: '提交成功',
        icon: 'success'
      });

      // 返回上一页
      setTimeout(() => {
        wx.navigateBack();
      }, 1500);
    } catch (error) {
      console.error('提交签名失败:', error);
      wx.showToast({
        title: '提交失败',
        icon: 'error'
      });
    }
  }
}); 

注意:handleSubmit 提交的逻辑根据具体的业务写


signature.json

{
  "usingComponents": {
    "t-button": "tdesign-miniprogram/button/button"
  },
  "disableScroll": true,
  "pageOrientation": "landscape"
} 

注意:我是用的tdesign这个UI

"pageOrientation": "landscape"这个是设置横屏


就是用canvas画,小程序里这种需求一般都是用canvas

收工,有需要copy去吧,哈哈哈哈哈哈哈哈哈哈


原文地址:https://blog.csdn.net/weixin_43106777/article/details/144391534

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!