怎么使用Vue Canvas实现电子签名

发布时间:2022-07-21 13:51:46 作者:iii
来源:亿速云 阅读:147

怎么使用Vue Canvas实现电子签名

目录

  1. 引言
  2. Vue.js 简介
  3. Canvas 简介
  4. 项目初始化
  5. 创建 Vue 组件
  6. 实现电子签名功能
  7. 优化与扩展
  8. 总结
  9. 参考资料

引言

在现代Web应用中,电子签名功能变得越来越常见。无论是合同签署、表单提交还是其他需要用户确认的场景,电子签名都提供了一种便捷的方式来获取用户的确认。本文将详细介绍如何使用Vue.js和HTML5的Canvas技术来实现一个简单的电子签名功能。

Vue.js 简介

Vue.js 是一个用于构建用户界面的渐进式JavaScript框架。它的核心库专注于视图层,易于与其他库或现有项目集成。Vue.js 的设计目标是通过尽可能简单的API实现响应的数据绑定和组合的视图组件。

Canvas 简介

HTML5 的 <canvas> 元素提供了一个用于绘制图形的API。通过JavaScript,我们可以在Canvas上绘制各种图形、文本、图像等。Canvas 非常适合用于实现绘图、动画、游戏等需要动态图形渲染的场景。

项目初始化

在开始之前,我们需要创建一个新的Vue项目。如果你还没有安装Vue CLI,可以通过以下命令进行安装:

npm install -g @vue/cli

然后,创建一个新的Vue项目:

vue create vue-canvas-signature

在项目创建过程中,你可以选择默认配置或手动选择需要的特性。创建完成后,进入项目目录并启动开发服务器

cd vue-canvas-signature
npm run serve

创建 Vue 组件

src/components 目录下创建一个新的组件文件 SignaturePad.vue。这个组件将包含我们的电子签名功能。

<template>
  <div class="signature-pad">
    <canvas ref="canvas" @mousedown="startDrawing" @mousemove="draw" @mouseup="stopDrawing" @mouseleave="stopDrawing"></canvas>
    <div class="controls">
      <button @click="clearCanvas">清除</button>
      <button @click="saveSignature">保存</button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'SignaturePad',
  data() {
    return {
      isDrawing: false,
      lastX: 0,
      lastY: 0,
    };
  },
  methods: {
    startDrawing(event) {
      this.isDrawing = true;
      const canvas = this.$refs.canvas;
      const rect = canvas.getBoundingClientRect();
      this.lastX = event.clientX - rect.left;
      this.lastY = event.clientY - rect.top;
    },
    draw(event) {
      if (!this.isDrawing) return;
      const canvas = this.$refs.canvas;
      const ctx = canvas.getContext('2d');
      const rect = canvas.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;

      ctx.beginPath();
      ctx.moveTo(this.lastX, this.lastY);
      ctx.lineTo(x, y);
      ctx.stroke();

      this.lastX = x;
      this.lastY = y;
    },
    stopDrawing() {
      this.isDrawing = false;
    },
    clearCanvas() {
      const canvas = this.$refs.canvas;
      const ctx = canvas.getContext('2d');
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    },
    saveSignature() {
      const canvas = this.$refs.canvas;
      const image = canvas.toDataURL('image/png');
      const link = document.createElement('a');
      link.href = image;
      link.download = 'signature.png';
      link.click();
    },
  },
  mounted() {
    const canvas = this.$refs.canvas;
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;
    const ctx = canvas.getContext('2d');
    ctx.strokeStyle = '#000';
    ctx.lineWidth = 2;
    ctx.lineCap = 'round';
  },
};
</script>

<style scoped>
.signature-pad {
  display: flex;
  flex-direction: column;
  align-items: center;
}

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

.controls {
  margin-top: 10px;
}

button {
  margin: 0 5px;
  padding: 5px 10px;
  cursor: pointer;
}
</style>

实现电子签名功能

6.1 初始化 Canvas

mounted 钩子中,我们初始化了Canvas的宽度和高度,并设置了绘图上下文的一些默认属性,如线条颜色、宽度和线条端点的样式。

mounted() {
  const canvas = this.$refs.canvas;
  canvas.width = canvas.offsetWidth;
  canvas.height = canvas.offsetHeight;
  const ctx = canvas.getContext('2d');
  ctx.strokeStyle = '#000';
  ctx.lineWidth = 2;
  ctx.lineCap = 'round';
}

6.2 监听鼠标事件

我们监听了Canvas的 mousedownmousemovemouseupmouseleave 事件,以便在用户开始绘制、移动鼠标、停止绘制或离开Canvas时执行相应的操作。

startDrawing(event) {
  this.isDrawing = true;
  const canvas = this.$refs.canvas;
  const rect = canvas.getBoundingClientRect();
  this.lastX = event.clientX - rect.left;
  this.lastY = event.clientY - rect.top;
},
draw(event) {
  if (!this.isDrawing) return;
  const canvas = this.$refs.canvas;
  const ctx = canvas.getContext('2d');
  const rect = canvas.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;

  ctx.beginPath();
  ctx.moveTo(this.lastX, this.lastY);
  ctx.lineTo(x, y);
  ctx.stroke();

  this.lastX = x;
  this.lastY = y;
},
stopDrawing() {
  this.isDrawing = false;
},

6.3 绘制签名

draw 方法中,我们使用Canvas的绘图API来绘制线条。通过 beginPathmoveTolineTo 方法,我们可以在Canvas上绘制出用户鼠标移动的路径。

6.4 清除签名

clearCanvas 方法使用 clearRect 方法清除Canvas上的所有内容,从而实现清除签名的功能。

clearCanvas() {
  const canvas = this.$refs.canvas;
  const ctx = canvas.getContext('2d');
  ctx.clearRect(0, 0, canvas.width, canvas.height);
},

6.5 保存签名

saveSignature 方法将Canvas上的内容转换为图像,并通过创建一个 <a> 元素来触发下载。

saveSignature() {
  const canvas = this.$refs.canvas;
  const image = canvas.toDataURL('image/png');
  const link = document.createElement('a');
  link.href = image;
  link.download = 'signature.png';
  link.click();
},

优化与扩展

7.1 支持触摸设备

为了支持触摸设备,我们需要添加对 touchstarttouchmovetouchend 事件的监听。

<template>
  <div class="signature-pad">
    <canvas ref="canvas" 
            @mousedown="startDrawing" 
            @mousemove="draw" 
            @mouseup="stopDrawing" 
            @mouseleave="stopDrawing"
            @touchstart="startDrawingTouch"
            @touchmove="drawTouch"
            @touchend="stopDrawing"></canvas>
    <div class="controls">
      <button @click="clearCanvas">清除</button>
      <button @click="saveSignature">保存</button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'SignaturePad',
  data() {
    return {
      isDrawing: false,
      lastX: 0,
      lastY: 0,
    };
  },
  methods: {
    startDrawing(event) {
      this.isDrawing = true;
      const canvas = this.$refs.canvas;
      const rect = canvas.getBoundingClientRect();
      this.lastX = event.clientX - rect.left;
      this.lastY = event.clientY - rect.top;
    },
    startDrawingTouch(event) {
      this.isDrawing = true;
      const canvas = this.$refs.canvas;
      const rect = canvas.getBoundingClientRect();
      const touch = event.touches[0];
      this.lastX = touch.clientX - rect.left;
      this.lastY = touch.clientY - rect.top;
    },
    draw(event) {
      if (!this.isDrawing) return;
      const canvas = this.$refs.canvas;
      const ctx = canvas.getContext('2d');
      const rect = canvas.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;

      ctx.beginPath();
      ctx.moveTo(this.lastX, this.lastY);
      ctx.lineTo(x, y);
      ctx.stroke();

      this.lastX = x;
      this.lastY = y;
    },
    drawTouch(event) {
      if (!this.isDrawing) return;
      const canvas = this.$refs.canvas;
      const ctx = canvas.getContext('2d');
      const rect = canvas.getBoundingClientRect();
      const touch = event.touches[0];
      const x = touch.clientX - rect.left;
      const y = touch.clientY - rect.top;

      ctx.beginPath();
      ctx.moveTo(this.lastX, this.lastY);
      ctx.lineTo(x, y);
      ctx.stroke();

      this.lastX = x;
      this.lastY = y;
    },
    stopDrawing() {
      this.isDrawing = false;
    },
    clearCanvas() {
      const canvas = this.$refs.canvas;
      const ctx = canvas.getContext('2d');
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    },
    saveSignature() {
      const canvas = this.$refs.canvas;
      const image = canvas.toDataURL('image/png');
      const link = document.createElement('a');
      link.href = image;
      link.download = 'signature.png';
      link.click();
    },
  },
  mounted() {
    const canvas = this.$refs.canvas;
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;
    const ctx = canvas.getContext('2d');
    ctx.strokeStyle = '#000';
    ctx.lineWidth = 2;
    ctx.lineCap = 'round';
  },
};
</script>

7.2 添加撤销功能

为了实现撤销功能,我们可以使用一个数组来存储每一步的绘图操作。每次绘制时,我们将当前Canvas的状态保存到数组中。当用户点击撤销按钮时,我们可以从数组中恢复上一个状态。

data() {
  return {
    isDrawing: false,
    lastX: 0,
    lastY: 0,
    history: [],
  };
},
methods: {
  startDrawing(event) {
    this.isDrawing = true;
    const canvas = this.$refs.canvas;
    const rect = canvas.getBoundingClientRect();
    this.lastX = event.clientX - rect.left;
    this.lastY = event.clientY - rect.top;
    this.saveState();
  },
  draw(event) {
    if (!this.isDrawing) return;
    const canvas = this.$refs.canvas;
    const ctx = canvas.getContext('2d');
    const rect = canvas.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    ctx.beginPath();
    ctx.moveTo(this.lastX, this.lastY);
    ctx.lineTo(x, y);
    ctx.stroke();

    this.lastX = x;
    this.lastY = y;
  },
  stopDrawing() {
    this.isDrawing = false;
    this.saveState();
  },
  saveState() {
    const canvas = this.$refs.canvas;
    const image = canvas.toDataURL();
    this.history.push(image);
  },
  undo() {
    if (this.history.length > 1) {
      this.history.pop();
      const canvas = this.$refs.canvas;
      const ctx = canvas.getContext('2d');
      const image = new Image();
      image.src = this.history[this.history.length - 1];
      image.onload = () => {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(image, 0, 0);
      };
    }
  },
  clearCanvas() {
    const canvas = this.$refs.canvas;
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    this.history = [];
    this.saveState();
  },
  saveSignature() {
    const canvas = this.$refs.canvas;
    const image = canvas.toDataURL('image/png');
    const link = document.createElement('a');
    link.href = image;
    link.download = 'signature.png';
    link.click();
  },
},

7.3 添加重做功能

重做功能与撤销功能类似,我们可以使用另一个数组来存储被撤销的操作。当用户点击重做按钮时,我们可以从该数组中恢复被撤销的操作。

data() {
  return {
    isDrawing: false,
    lastX: 0,
    lastY: 0,
    history: [],
    redoHistory: [],
  };
},
methods: {
  startDrawing(event) {
    this.isDrawing = true;
    const canvas = this.$refs.canvas;
    const rect = canvas.getBoundingClientRect();
    this.lastX = event.clientX - rect.left;
    this.lastY = event.clientY - rect.top;
    this.saveState();
  },
  draw(event) {
    if (!this.isDrawing) return;
    const canvas = this.$refs.canvas;
    const ctx = canvas.getContext('2d');
    const rect = canvas.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    ctx.beginPath();
    ctx.moveTo(this.lastX, this.lastY);
    ctx.lineTo(x, y);
    ctx.stroke();

    this.lastX = x;
    this.lastY = y;
  },
  stopDrawing() {
    this.isDrawing = false;
    this.saveState();
  },
  saveState() {
    const canvas = this.$refs.canvas;
    const image = canvas.toDataURL();
    this.history.push(image);
    this.redoHistory = [];
  },
  undo() {
    if (this.history.length > 1) {
      const lastState = this.history.pop();
      this.redoHistory.push(lastState);
      const canvas = this.$refs.canvas;
      const ctx = canvas.getContext('2d');
      const image = new Image();
      image.src = this.history[this.history.length - 1];
      image.onload = () => {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(image, 0, 0);
      };
    }
  },
  redo() {
    if (this.redoHistory.length > 0) {
      const nextState = this.redoHistory.pop();
      this.history.push(nextState);
      const canvas = this.$refs.canvas;
      const ctx = canvas.getContext('2d');
      const image = new Image();
      image.src = nextState;
      image.onload = () => {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(image, 0, 0);
      };
    }
  },
  clearCanvas() {
    const canvas = this.$refs.canvas;
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    this.history = [];
    this.redoHistory = [];
    this.saveState();
  },
  saveSignature() {
    const canvas = this.$refs.canvas;
    const image = canvas.toDataURL('image/png');
    const link = document.createElement('a');
    link.href = image;
    link.download = 'signature.png';
    link.click();
  },
},

7.4 添加签名验证

在某些场景下,我们可能需要对用户的签名进行验证,以确保签名的有效性。我们可以通过检查Canvas上是否有绘制内容来实现简单的签名验证。

methods: {
  isSignatureValid() {
    const canvas = this.$refs.canvas;
    const ctx = canvas.getContext('2d');
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;

    for (let i = 0; i < data.length; i += 4) {
      if (data[i + 3] !== 0) {
        return true;
      }
    }
    return false;
  },
  saveSignature() {
    if (!this.isSignatureValid()) {
      alert('请先签名');
      return;
    }
    const canvas = this.$refs.canvas;
    const image = canvas.toDataURL('image/png');
    const link = document.createElement('a');
    link.href = image;
    link.download = 'signature.png';
    link.click();
  },
},

总结

通过本文的介绍,我们学习了如何使用Vue.js和HTML5的Canvas技术来实现一个简单的电子签名功能。我们实现了基本的绘制、清除、保存功能,并进一步优化

推荐阅读:
  1. 怎么在vue中使用canvas手写电子签名
  2. 使用vue实现一个电子签名组件的示例代码

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vue canvas

上一篇:Python如何实现删除windows下的长路径文件

下一篇:python与json数据的交互实例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》