react实现电子签名

react实现电子签名

效果图

在这里插入图片描述

在项目中安装 react-signature-canvas

命令:

npm install react-signature-canvas --save

react电子签名组件封装

import { Button } from 'antd';
import React, { useRef } from 'react';
import SignatureCanvas from 'react-signature-canvas';

const ElectronicSignature = () => {
  const signatureRef = useRef();

  // 处理保存签名的方法
  const handleSaveSignature = () => {
    const signatureData = signatureRef.current.toDataURL(); // 将签名保存为DataURL
    console.log(signatureData, '999999999'); // 这里可以将签名数据传送到后端保存或处理
  };

  // 清除签名
  const handleClearSignature = () => {
    signatureRef.current.clear();
  };

  return (
    <div>
      <h2>电子签名</h2>
      <div>
        <SignatureCanvas
          ref={signatureRef}
          penColor="black" // 可以设置笔的颜色
          canvasProps={{ width: 500, height: 200, className: 'signature-canvas' }} // 设置Canvas的尺寸和样式
        />
      </div>
      <div>
        <Button onClick={handleSaveSignature}>保存签名</Button>
        <Button onClick={handleClearSignature}>清除签名</Button>
      </div>
    </div>
  );
};

export default ElectronicSignature;

电子签名(原生版)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <canvas></canvas>
    <div>
      <button onclick="cancel()">取消</button>
      <button onclick="save()">保存</button>
    </div>
  </body>
  <script>
    // 配置内容
    const config = {
      width: 400, // 宽度
      height: 200, // 高度
      lineWidth: 5, // 线宽
      strokeStyle: 'red', // 线条颜色
      lineCap: 'round', // 设置线条两端圆角
      lineJoin: 'round', // 线条交汇处圆角
    };

    // 获取canvas 实例
    const canvas = document.querySelector('canvas');
    // 设置宽高
    canvas.width = config.width;
    canvas.height = config.height;
    // 设置一个边框
    canvas.style.border = '1px solid #000';
    // 创建上下文
    const ctx = canvas.getContext('2d');

    // 设置填充背景色
    ctx.fillStyle = 'transparent';
    // 绘制填充矩形
    ctx.fillRect(
      0, // x 轴起始绘制位置
      0, // y 轴起始绘制位置
      config.width, // 宽度
      config.height, // 高度
    );

    // 保存上次绘制的 坐标及偏移量
    const client = {
      offsetX: 0, // 偏移量
      offsetY: 0,
      endX: 0, // 坐标
      endY: 0,
    };

    // 判断是否为移动端
    const mobileStatus = /Mobile|Android|iPhone/i.test(navigator.userAgent);

    // 初始化
    const init = (event) => {
      // 获取偏移量及坐标
      const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event;

      // 修改上次的偏移量及坐标
      client.offsetX = offsetX;
      client.offsetY = offsetY;
      client.endX = pageX;
      client.endY = pageY;

      // 清除以上一次 beginPath 之后的所有路径,进行绘制
      ctx.beginPath();
      // 根据配置文件设置相应配置
      ctx.lineWidth = config.lineWidth;
      ctx.strokeStyle = config.strokeStyle;
      ctx.lineCap = config.lineCap;
      ctx.lineJoin = config.lineJoin;
      // 设置画线起始点位
      ctx.moveTo(client.endX, client.endY);
      // 监听 鼠标移动或手势移动
      window.addEventListener(mobileStatus ? 'touchmove' : 'mousemove', draw);
    };
    // 绘制
    const draw = (event) => {
      // 获取当前坐标点位
      const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event;
      // 修改最后一次绘制的坐标点
      client.endX = pageX;
      client.endY = pageY;

      // 根据坐标点位移动添加线条
      ctx.lineTo(pageX, pageY);

      // 绘制
      ctx.stroke();
    };
    // 结束绘制
    const cloaseDraw = () => {
      // 结束绘制
      ctx.closePath();
      // 移除鼠标移动或手势移动监听器
      window.removeEventListener('mousemove', draw);
    };
    // 创建鼠标/手势按下监听器
    window.addEventListener(mobileStatus ? 'touchstart' : 'mousedown', init);
    // 创建鼠标/手势 弹起/离开 监听器
    window.addEventListener(mobileStatus ? 'touchend' : 'mouseup', cloaseDraw);

    // 取消-清空画布
    const cancel = () => {
      // 清空当前画布上的所有绘制内容
      ctx.clearRect(0, 0, config.width, config.height);
    };
    // 保存-将画布内容保存为图片
    const save = () => {
      // 将canvas上的内容转成blob流
      canvas.toBlob((blob) => {
        // 获取当前时间并转成字符串,用来当做文件名
        const date = Date.now().toString();
        // 创建一个 a 标签
        const a = document.createElement('a');
        // 设置 a 标签的下载文件名
        a.download = `${date}.png`;
        // 设置 a 标签的跳转路径为 文件流地址
        a.href = URL.createObjectURL(blob);
        // 手动触发 a 标签的点击事件
        a.click();
        // 移除 a 标签
        a.remove();
      });
    };
  </script>
</html>

以上代码实现步骤:
1、在body中添加canvas标签
在在body中添加canvas标签,添加两个按钮,取消和保存。

<body>
    <canvas></canvas>
    <div>
        <button>取消</button>
        <button>保存</button>
    </div>
</body>

2、添加文件
这里全程使用js进行样式设置及添加。

// 配置内容
    const config = {
        width: 400, // 宽度
        height: 200, // 高度
        lineWidth: 5, // 线宽
        strokeStyle: 'red', // 线条颜色
        lineCap: 'round', // 设置线条两端圆角
        lineJoin: 'round', // 线条交汇处圆角
    }

3、获取canvas实例
使用querySelector获取canvas的dom实例,并设置样式和创建上下文。

    // 获取canvas 实例
    const canvas = document.querySelector('canvas')
    // 设置宽高
    canvas.width = config.width
    canvas.height = config.height
    // 设置一个边框,方便我们查看及使用
    canvas.style.border = '1px solid #000'
    // 创建上下文
    const ctx = canvas.getContext('2d')

4、基础设置
将canvas的填充色为透明,绘制填充一个矩形,作为画布,如果不设置这个填充背景色,在初始渲染的时候是一个黑色背景,即默认色。

    // 设置填充背景色
    ctx.fillStyle = 'transparent'
    // 绘制填充矩形
    ctx.fillRect(
        0, // x 轴起始绘制位置
        0, // y 轴起始绘制位置
        config.width, // 宽度
        config.height // 高度
    );

5、上次绘制路径保存
这里需要声明一个对象,用来记录上一次绘制的路径结束坐标点及偏移量。

  • 为啥需要保存偏移量呢,因为鼠标和画布上的距离是存在一定的偏移距离,在我们绘制的过程中需要减去这个偏移量,才是我们实际的绘制坐标。
  • 但我发现chrome中不需要减去这个偏移量,拿到的就是实际的坐标,之前在微信小程序中使用就需要减去偏移量,需要在小程序中使用的朋友需要注意这一点。
    // 保存上次绘制的 坐标及偏移量
    const client = {
        offsetX: 0, // 偏移量
        offsetY: 0,
        endX: 0, // 坐标
        endY: 0
    }

6、设备兼容
需要它不仅可以在web端使用,还需要在移动端使用,需要给它做设备兼容处理。通过调用navigator.userAgent获取当前设备信息,进行正则匹配判断。

// 判断是否为移动端
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent))

7、初始化
在监听鼠标按下(mousedown)(web端)/触摸开始(touchstart)的时候进行初始化,事件监听采用addEventListener

// 创建鼠标/手势按下监听器
window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init)

8、声明初始化方法
添加一个init方法作为监听鼠标按下/触摸开始的回调方法。
需要获取到当前鼠标按下/触摸开始的偏移量和坐标,进行起始点绘制。
web端可以直接通过event中取到,而移动端则需要在event.changedTouches[0]中取到。

    // 初始化
    const init = event => {
        // 获取偏移量及坐标
        const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event 

        // 修改上次的偏移量及坐标
        client.offsetX = offsetX
        client.offsetY = offsetY
        client.endX = pageX
        client.endY = pageY

        // 清除以上一次 beginPath 之后的所有路径,进行绘制
        ctx.beginPath()

        // 根据配置文件设置进行相应配置
        ctx.lineWidth = config.lineWidth
        ctx.strokeStyle = config.strokeStyle
        ctx.lineCap = config.lineCap
        ctx.lineJoin = config.lineJoin

        // 设置画线起始点位
        ctx.moveTo(client.endX, client.endY)

        // 监听 鼠标移动或手势移动
        window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
    }

9、绘制
添加绘制draw方法,作为监听鼠标移动/触摸移动的回调方法

    // 绘制
    const draw = event => {
        // 获取当前坐标点位
        const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
        // 修改最后一次绘制的坐标点
        client.endX = pageX
        client.endY = pageY

        // 根据坐标点位移动添加线条
        ctx.lineTo(pageX , pageY )

        // 绘制
        ctx.stroke()
    }

10、结束绘制
添加了监听鼠标移动/触摸移动一定要记得取消监听并结束绘制,不然的话它会一直监听并绘制的。
这里创建一个cloaseDraw方法作为鼠标弹起/结束触摸的回调方法来结束绘制并移除鼠标移动/触摸移动的监听。
canvas结束绘制则需要调用closePath()让其结束绘制

    // 结束绘制
    const cloaseDraw = () => {
        // 结束绘制
        ctx.closePath()
        // 移除鼠标移动或手势移动监听器
        window.removeEventListener("mousemove", draw)
    }

添加结束回调监听器

// 创建鼠标/手势 弹起/离开 监听器
    window.addEventListener(mobileStatus ? "touchend" :"mouseup", cloaseDraw)

11、取消功能/清空画布
创建一个cancel的方法作为取消并清空画布使用

    // 取消-清空画布
    const cancel = () => {
        // 清空当前画布上的所有绘制内容
        ctx.clearRect(0, 0, config.width, config.height)
    }

绑定

  <button onclick="cancel()">取消</button>

12、保存功能
创建一个save的方法作为保存画布上的内容使用。
将画布上的内容保存为图片/文件的方法有很多,比较常见的是blob和toDataURL这两种方案,但toDataURL这哥们没blob强,适配也不咋滴。所以我们这里采用a标签 ➕ blob方案实现图片的保存下载。

    // 保存-将画布内容保存为图片
    const save = () => {
        // 将canvas上的内容转成blob流
        canvas.toBlob(blob => {
            // 获取当前时间并转成字符串,用来当做文件名
            const date = Date.now().toString()
            // 创建一个 a 标签
            const a = document.createElement('a')
            // 设置 a 标签的下载文件名
            a.download = `${date}.png`
            // 设置 a 标签的跳转路径为 文件流地址
            a.href = URL.createObjectURL(blob)
            // 手动触发 a 标签的点击事件
            a.click()
            // 移除 a 标签
            a.remove()
        })
    }

绑定

 <button onclick="save()">保存</button>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值