canvas 制作兼容 PC 和手机端签名插件

1、首先我们来了解一下 canvas 的基本使用

在 canvas 标签中间写的内容会在浏览器不兼容的情况下显示

<canvas class="canvas" ref="canvas">
    抱歉,您的浏览器不支持canvas元素
</canvas>

我们先来熟悉一下本次任务中 canvas 使用的API(其他 API 可参考 https://blog.csdn.net/Insist_bin/article/details/80282043

const canvas = document.getElementQuerySelector('canvas');
// 获取 canvas 上下文
const cxt = canvas.getContext('2d');
// 设置 canvas 颜色
cxt.strokeStyle = '#000';
// 设置 canvas 线条宽度
cxt.lineWidth = 3;
// 改变线条末端线帽的样式,为每个末端添加圆形线帽,减少线条的生硬感
cxt.lineCap = 'round';
// 指定条线交汇时为圆形边角
cxt.lineJoin = 'round';
// 绘制元素阴影的功能来模糊边缘出现的锯齿
cxt.shadowBlur = 1;
cxt.shadowColor = '#000';

// 清除当前路径,开始新的路径
context.beginPath();
// 设置绘制起始坐标
cxt.moveTo(10, 10); // 就是从 x = 10, y = 10 的坐标开始绘制
// 设置直线到的位置
cxt.lineTo(10, 100);  // 就是从 x = 10, y = 10 绘制到  x = 10, y = 100 的一条路径
// 绘制完路径之后需要描边
cxt.stroke();

// 注意点绘制的都是路径,需要通过 stroke 描边才能显示

 使用到的事件

  • mousedown:PC 端鼠标按下
  • mousemove:PC 端鼠标移动
  • mouseup:PC 端松起鼠标
  • touchstart:当手指触摸屏幕时候触发
  • touchmove:当手机在滑动屏幕的时候连续触发
  • touchend:当手指从屏幕上离开的时候触发

下面我们开始在 Vue 项目中创建 signature 组件了

整体的思路是:鼠标点下去那一刻,记录点击那点的坐标,并开始监听移动事件,每次触发移动事件的时候,获取移动的坐标,然后把起始坐标到结束坐标绘制线,接着把移动的坐标再次作为起始坐标,由于移动事件会不断的触发,不断触发移动事件就能不断绘制一点一点,最终形成路径。当鼠标松开的时候记得取消监听移动事件,不然会一直绘制下去。

<template>
  <div>
    <div class="signature">
      <canvas class="canvas" ref="canvas">
        抱歉,您的浏览器不支持canvas元素
      </canvas>
      <div class="button-box">
        <button @click="surewrite">确定</button>
        <button @click="overwrite">重写</button>
      </div>
    </div>
  </div>
</template>
export default {
  name: "signature",
  // 可自定义宽高
  props: {
    height: {
      type: Number,
      default: 150
    },
    width: {
      type: Number,
      default: 300
    }
  },
  data() {
    return {
      canvas: null,
      cxt: null,
      // 判断当前设备是手机还是电脑
      device: ('ontouchstart' in window) ? 'phone' : 'computer',
      // 根据设备定义不同的事件组
      events: ('ontouchstart' in window) ?
        ['touchstart', 'touchmove', 'touchend'] :
        ['mousedown', 'mousemove', 'mouseup'],
      startX: 0,
      startY: 0,
      lineWidth: 3,
      isDraw: false, // 表示canvas上是否已经签过名,哪怕是一个点
      drawSuc: false // 点击签名成功
    };
  },
  mounted() {
    // 因为需要操作 DOM 所以初始化 canvas 需要放在 mounted 中
    this.initCanvas()
  },
  methods: {
    // 初始化 canvas
    initCanvas() {
      const canvas = this.$refs.canvas;
      canvas.width = this.width;
      canvas.height = this.height;

      this.canvas = canvas;

      const cxt = canvas.getContext('2d');
      this.rect = canvas.getBoundingClientRect();
      this.cxt = cxt;
      cxt.strokeStyle = '#000';
      cxt.lineCap = 'round';
      cxt.lineWidth = this.lineWidth;
      cxt.lineJoin = 'round';
      cxt.shadowBlur = 1;
      cxt.shadowColor = '#000';

      // 为 canvas 监听第一个事件
      canvas.addEventListener(this.events[0], this.startEventHandler, false)
    },
    // 传入起始点和终点绘制
    drawLine(context, startX, startY, moveX, moveY) {
      context.beginPath();
      context.moveTo(startX, startY)
      context.lineTo(moveX, moveY)
      context.stroke();
      context.closePath();
    },
    startEventHandler(e) {
      // 如果已经点击确认签名了则不能修改了,除非点击重写
      if (this.drawSuc)
        return
      let ev = e || event;
      ev.preventDefault();
      // offsetX/Y 是相对于带有定位的父盒子的x,y坐标
      // 因为 offsetX 和 offsetY 在火狐不兼容
      // 所以使用 clientX - rect.left
      // clientX/Y 鼠标相对于浏览器窗口可视区域的X,Y坐标的距离
      // rect.left/top 元素距离页面左边和上边的距离

      this.cxt.beginPath()
      // 记录起始点
      if (this.device === 'computer') {
        let rect = this.canvas.getBoundingClientRect()
        this.startX = ev.clientX - rect.left;
        this.startY = ev.clientY - rect.top;
      } else {
        const touch = e.changedTouches[0];
        this.startX = touch.pageX;
        this.startY = touch.pageY;
      }
      this.canvas.addEventListener(this.events[1], this.moveEventHandler, false);
      this.isDraw = true;
    },
    moveEventHandler(e) {
      let ev = e || event;
      let moveX;
      let moveY;
      this.cxt.beginPath()
      if (this.device === 'computer') {
        let rect = this.canvas.getBoundingClientRect()
        moveX = ev.clientX - rect.left;
        moveY = ev.clientY - rect.top;
      } else {
        const touch = e.changedTouches[0];
        moveX = touch.pageX;
        moveY = touch.pageY;
      }
      this.drawLine(this.cxt, this.startX, this.startY, moveX, moveY);
      this.startX = moveX;
      this.startY = moveY;
      this.canvas.addEventListener(this.events[2], this.endEventHandler, false);
    },
    endEventHandler() {
      this.cxt.closePath();
      this.canvas.removeEventListener(this.events[1], this.moveEventHandler)
    },
    //重写
    overwrite() {
      this.cxt.clearRect(0, 0, this.width, this.height);
      this.isDraw = false;
      this.drawSuc = false
    },
    //确认签名
    surewrite() {
      // 确认签名后把 canvas 转换成图片
      const imgBase64 = this.canvas.toDataURL();
      console.log("保存签名成功" + imgBase64);
      this.drawSuc = true
      if (this.isDraw) {
        alert("签名成功!");
        // 把图片通过回调方式返回给外部
        this.$emit("surewrite", imgBase64);
      } else {
        alert("请签名后再确认!");
      }
    }
  }
}
    
  .canvas {
    border: 1px solid #000;
  }

  .signature {
    box-sizing: border-box;
    overflow: hidden;
    z-index: 100;
    display: flex;
  }

  .button-box {
    padding: 5px;
    text-align: center;
    display: flex;
    flex-direction: column;
  }

  .btnBox {
    display: flex;
    flex-direction: column;
    padding: 5px;
    text-align: center;
    line-height: 30px;
  }

  .button-box button {
    border: 1px solid dodgerblue;
    background: dodgerblue;
    color: #fff;
    border-radius: 4px;
    padding: 1px 25px;
    width: 80px;
    margin: 10px 15px;
    font-size: 14px;
  }

这张图表示的是client,screen,offset 的区别

下面是效果图

<signature :width="600" :height="500"></signature>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Canvas可以用来实现签名插件。下面是一个简单的示例,演示如何使用Canvas来实现一个基本的签名功能: 首先,你需要在HTML中创建一个Canvas元素来绘制签名: ```html <canvas id="signatureCanvas" width="400" height="200"></canvas> ``` 接下来,在JavaScript中,你可以使用以下代码来获取Canvas元素和相关的上下文对象,并设置一些基本的绘图属性: ```javascript var canvas = document.getElementById("signatureCanvas"); var context = canvas.getContext("2d"); context.strokeStyle = "#000"; // 设置绘图颜色 context.lineWidth = 2; // 设置线宽 ``` 然后,你可以编写一些事件处理程序来响应用户的绘图操作。例如,当用户按下鼠标按钮时,开始记录鼠标移动的路径,并在Canvas上绘制线条: ```javascript var isDrawing = false; var lastX = 0; var lastY = 0; canvas.addEventListener("mousedown", function(e) { isDrawing = true; [lastX, lastY] = [e.offsetX, e.offsetY]; // 记录鼠标按下时的坐标 }); canvas.addEventListener("mousemove", function(e) { if (!isDrawing) return; context.beginPath(); context.moveTo(lastX, lastY); context.lineTo(e.offsetX, e.offsetY); context.stroke(); [lastX, lastY] = [e.offsetX, e.offsetY]; // 更新坐标 }); canvas.addEventListener("mouseup", function() { isDrawing = false; }); canvas.addEventListener("mouseout", function() { isDrawing = false; }); ``` 最后,你可以添加一些其他功能,比如清除签名、保存签名等。例如,你可以在HTML中添加按钮来触发这些功能: ```html <button onclick="clearSignature()">清除签名</button> <button onclick="saveSignature()">保存签名</button> ``` 在JavaScript中,你可以实现这些功能,比如清除签名的代码如下: ```javascript function clearSignature() { context.clearRect(0, 0, canvas.width, canvas.height); } function saveSignature() { // 将Canvas内容转换为Base64图像数据 var dataURL = canvas.toDataURL(); // 创建一个链接并下载签名图像 var link = document.createElement("a"); link.href = dataURL; link.download = "signature.png"; link.click(); } ``` 这只是一个简单的示例,你可以根据自己的需求进行扩展和定制。希望对你有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值