手把手教你封装一个uniapp vue3组合式API手写签名组件

 

前言

在移动端开发中,手写签名功能是一个非常常见的需求。本文将手把手教你如何在uniapp中使用vue3的组合式API封装一个手写签名弹出框组件。通过封装,我们可以在项目中轻松复用该组件,提高开发效率。

实现步骤

1. 组件设计与功能

  • 手写签名:用户可以在 canvas 上绘制签名。

  • 重置功能:清除画布内容,重新签名。

  • 保存功能:将签名保存为图片,并生成 base64 或临时文件路径。

  • 预览功能:预览签名图片。

  • 横屏适配:支持横屏模式,提升用户体验。

2. 组件代码实现

2.1 模板部分 (template)

<template>
  <view class="signature-container">
    <!-- 画布区域 -->
    <canvas
      canvas-id="signatureCanvas"
      class="signature-canvas"
      disable-scroll="true"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
    ></canvas>

    <!-- 操作按钮 -->
    <view class="button-group">
      <button @click="handleReset">重置</button>
      <button @click="handleSave">保存</button>
      <button @click="handlePreview">预览</button>
    </view>
  </view>
</template>

2.2 脚本部分 (script

<script>
export default {
  data() {
    return {
      ctx: null, // canvas 上下文
      points: [], // 存储绘制路径点
      canvasWidth: 0, // 画布宽度
      canvasHeight: 0, // 画布高度
      tempFilePath: "", // 临时文件路径
    };
  },
  mounted() {
    this.initCanvas();
  },
  methods: {
    // 初始化画布
    initCanvas() {
      const query = uni.createSelectorQuery().in(this);
      query
        .select(".signature-canvas")
        .boundingClientRect((rect) => {
          this.canvasWidth = rect.width;
          this.canvasHeight = rect.height;
          this.ctx = uni.createCanvasContext("signatureCanvas", this);
          this.ctx.lineWidth = 4; // 设置线条宽度
          this.ctx.lineCap = "round"; // 设置线条端点样式
          this.ctx.lineJoin = "round"; // 设置线条交点样式
        })
        .exec();
    },

    // 触摸开始
    handleTouchStart(e) {
      const startX = e.touches[0].x;
      const startY = e.touches[0].y;
      this.points.push({ x: startX, y: startY });
      this.ctx.beginPath();
      this.ctx.moveTo(startX, startY);
    },

    // 触摸移动
    handleTouchMove(e) {
      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 point1 = this.points[this.points.length - 2];
        const point2 = this.points[this.points.length - 1];
        this.ctx.moveTo(point1.x, point1.y);
        this.ctx.lineTo(point2.x, point2.y);
        this.ctx.stroke();
        this.ctx.draw(true);
      }
    },

    // 触摸结束
    handleTouchEnd() {
      this.points = [];
    },

    // 重置画布
    handleReset() {
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      this.ctx.draw(true);
      this.tempFilePath = "";
    },

    // 保存签名
    handleSave() {
      if (this.points.length === 0) {
        uni.showToast({ title: "请先签名", icon: "none" });
        return;
      }
      uni.canvasToTempFilePath({
        canvasId: "signatureCanvas",
        success: (res) => {
          this.tempFilePath = res.tempFilePath;
          uni.showToast({ title: "保存成功", icon: "success" });
          this.$emit("save", res.tempFilePath); // 触发保存事件
        },
        fail: (err) => {
          console.error("保存失败", err);
        },
      });
    },

    // 预览签名
    handlePreview() {
      if (!this.tempFilePath) {
        uni.showToast({ title: "请先保存签名", icon: "none" });
        return;
      }
      uni.previewImage({
        urls: [this.tempFilePath],
      });
    },
  },
};
</script>

2.3 样式部分 (style

<style scoped>
.signature-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
}

.signature-canvas {
  width: 100%;
  height: 300px;
  border: 1px solid #ccc;
  background-color: #fff;
}

.button-group {
  margin-top: 20px;
  display: flex;
  justify-content: space-around;
  width: 100%;
}

button {
  flex: 1;
  margin: 0 10px;
}
</style>

3. 使用示例

在父组件中引入并使用该签名组件:

<template>
  <view>
    <signature-component @save="handleSave"></signature-component>
  </view>
</template>

<script>
import SignatureComponent from "@/components/SignatureComponent.vue";

export default {
  components: {
    SignatureComponent,
  },
  methods: {
    handleSave(tempFilePath) {
      console.log("签名图片路径:", tempFilePath);
      // 可以将路径上传至服务器或进行其他处理
    },
  },
};
</script>

4. 注意事项

  1. 横屏适配:如果需要横屏模式,可以在 pages.json 中配置 pageOrientation: "landscape"

  2. 性能优化:对于复杂的签名路径,建议限制路径点的数量,避免内存占用过高。

  3. 兼容性:确保在微信开发者工具中测试,并检查真机运行效果。

通过以上实现,您可以快速在 uni-app 中封装一个功能完善的手写签名组件,并适配微信小程序平台。希望这篇文章能帮助你解决问题!如果有其他疑问,欢迎在评论区留言讨论! 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiaberrrr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值