h5 签名 vue

需求:在点击签名弹窗签名,点确定回显

1、封装一个.vue 文件,我是封装一个Signature.vue文件,放在components目录下

Signature.vue全部内容

javascript 复制代码
<template>
  <div class="signature">
    <canvas class="signature-canvas" ref="canvas" @touchstart="startDrawing" @touchmove="draw" @touchend="stopDrawing"></canvas>
  </div>
</template>

<script>
export default {
  name: 'Signature',
  data() {
    return {
      isDrawing: false,
      signatureData: [],
    };
  },
  methods: {
    startDrawing(event) {
      const canvas = this.$refs.canvas;
      const rect = canvas.getBoundingClientRect();
      const scaleX = canvas.width / rect.width;
      const scaleY = canvas.height / rect.height;
      const x = (event.touches[0].clientX - rect.left) * scaleX;
      const y = (event.touches[0].clientY - rect.top) * scaleY;

      const ctx = canvas.getContext('2d');
      ctx.beginPath();
      ctx.moveTo(x, y);

      this.isDrawing = true;
      this.signatureData.push({ x: x / canvas.width, y: y / canvas.height });
    },
    draw(event) {
      if (this.isDrawing) {
        const canvas = this.$refs.canvas;
        const rect = canvas.getBoundingClientRect();
        const scaleX = canvas.width / rect.width;
        const scaleY = canvas.height / rect.height;
        const x = (event.touches[0].clientX - rect.left) * scaleX;
        const y = (event.touches[0].clientY - rect.top) * scaleY;

        const ctx = canvas.getContext('2d');
        ctx.lineTo(x, y);
        ctx.stroke();

        this.signatureData.push({ x: x / canvas.width, y: y / canvas.height });
      }
    },

    stopDrawing() {
      this.isDrawing = false;
    },

    clear() {
      this.signatureData = [];

      const canvas = this.$refs.canvas;
      this.ctx = canvas.getContext('2d');
      this.ctx.clearRect(0, 0, canvas.width, canvas.height);
    },
  },
};
</script>

<style lang="less" scoped>
.signature {
  position: relative;
}

.signature-canvas {
  display: block;
  border: 1px solid black;
  margin: 10px;
  width: calc(100% - 20px);
  height: 200px;
}
</style>

在list.vue 文件引入使用 上述文件 components/Signature.vue,获取到的this.model.signList 就是签名

由很多坐标组成

javascript 复制代码
<template>
<div class="van-doc-block">
      <h2 class="van-doc-block-title">第二位维保人员签名确认<span>*</span></h2>
      <van-cell-group inset>
        <div class="signature-wrap" @click="openSignatureHandle('two')">
          <div class="write-inner-wrap">
            <div v-show="model.signList && model.signList.length" class="img-wrap">
              <canvas class="signature-canvas" ref="outputCanvas"></canvas>
            </div>
            <div v-show="!model.signList || model.signList.length === 0" class="no-sign-wrap">点击此处进入签名区域</div>
          </div>
        </div>
      </van-cell-group>
    <van-popup v-model="signatureVisible" closeable position="bottom" :style="{ height: '45%' }">
      <div class="signature-popup-wrap">
        <Signature ref="signature"></Signature>
        <div class="button-wrap">
          <van-button type="default" native-type="button" @click="signatureClearHandle">清除</van-button>
          <van-button type="primary" native-type="button" @click.stop="signatureOkHandle">确定</van-button>
        </div>
      </div>
    </van-popup>
    </div>
    </template>
    <script>
import Signature from '@/components/Signature'; // 引入上述文件
export default {
  components: { Signature },
  data() {
    return {
    signatureVisible: false,
      },
      methods: {
       signatureClearHandle() {
      this.$refs['signature'].clear();
    },
	signatureOkHandle() {
       const signatureData = lo.cloneDeep(this.$refs['signature'].signatureData);
        this.$set(this.model, 'signList', signatureData);
        this.drawSavedSignature(signatureData, 'outputCanvas');
      
    },
    drawSavedSignature(signatureData, canvasOut) {
      this.$nextTick(() => {
        const canvas = this.$refs[canvasOut];

        const ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        if (signatureData && signatureData.length) {
          ctx.beginPath();
          ctx.moveTo(signatureData[0].x * canvas.width, signatureData[0].y * canvas.height);

          for (let i = 1; i < signatureData.length; i++) {
            const currentPoint = signatureData[i];
            const previousPoint = signatureData[i - 1];

            // 检查当前点和前一个点之间的距离,如果距离过大,则认为是新的笔画
            const distance = Math.sqrt(Math.pow(currentPoint.x - previousPoint.x, 2) + Math.pow(currentPoint.y - previousPoint.y, 2));
            if (distance > 0.1) {
              ctx.moveTo(currentPoint.x * canvas.width, currentPoint.y * canvas.height);
            } else {
              ctx.lineTo(currentPoint.x * canvas.width, currentPoint.y * canvas.height);
            }
          }

          ctx.stroke();
        }

        this.signatureVisible = false;
      });
    },
    openSignatureHandle(type) {
      this.showSignType = type;
      this.$nextTick(() => {
        const $signatureRef = this.$refs['signature'];
        if ($signatureRef) {
          this.$refs['signature'].clear();
        }
      });

      this.signatureVisible = true;
    },
    }
    }
  }
   </script>
相关推荐
JieE21214 小时前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE21214 小时前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
kyriewen18 小时前
我用 AI 一周写完了整个项目,上线第一天就崩了——这是我踩过最贵的 5 个坑
前端·javascript·ai编程
Larcher18 小时前
AI Loop:让AI像人一样自主完成任务的核心机制
javascript·人工智能·设计模式
默_笙18 小时前
🃏 JS 只有 8 种数据类型,但我花了 2 天才搞懂 null 和 undefined 的区别
javascript
jump_jump19 小时前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
swipe20 小时前
正则表达式入门到进阶:从表单校验到手写模板引擎
前端·javascript·面试
kyriewen21 小时前
前端错误监控最全指南:捕获 JS 异常、Promise 拒绝、资源加载失败,附上报代码
前端·javascript·监控
大家的林语冰21 小时前
ESLint 近期动态大全,新版本正式发布,antfu 大佬推荐的插件也更新了!
前端·javascript·前端工程化
胡志辉1 天前
深入浅出 call、apply、bind
前端·javascript·后端