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>
相关推荐
killerbasd3 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌3 小时前
ES6——二进制数组详解
前端·ecmascript·es6
橘子编程4 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
叫我一声阿雷吧4 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint
大家的林语冰4 小时前
《前端周刊》尤大开源 Vite+ 全家桶,前端工业革命启动;尤大爆料 Void 云服务新产品,Vite 进军全栈开发;ECMA 源码映射规范......
前端·javascript·vue.js
jiayong235 小时前
第 8 课:开始引入组合式函数
前端·javascript·学习
天若有情6735 小时前
【C++原创开源】formort.h:一行头文件,实现比JS模板字符串更爽的链式拼接+响应式变量
开发语言·javascript·c++·git·github·开源项目·模版字符串
M ? A6 小时前
Vue 迁移 React 实战:VuReact 一键自动化转换方案
前端·vue.js·经验分享·react.js·开源·自动化·vureact
yuki_uix6 小时前
重排、重绘与合成——浏览器渲染性能的底层逻辑
前端·javascript·面试
Burt6 小时前
我的 2026 全栈选型:Vue3 + Elysia + Bun + AlovaJS
vue.js·全栈·bun