实现 React 电子签名功能:从零开始构建一个完整的解决方案

ops/2024/12/20 5:42:42/

需求概述

我们希望通过 React 构建一个简单的电子签名组件,用户可以在画布上手写签名,完成后可以保存签名并将其上传到服务器。具体需求如下:

  • 用户可以在画布上自由绘制签名。
  • 提供“清除”按钮,允许用户重置签名。
  • 提供“保存”按钮,将签名保存为图片文件并上传到服务器。
  • 签名应以 Base64 格式保存,并转换为文件流后上传。
  • 使用 MinIO 作为文件存储服务,确保签名文件的安全性和持久性。

技术栈选择

  • react-signature-canvas:一个轻量级的 React 组件,允许用户在画布上绘制签名。
  • minio.js:用于与 MinIO 服务器交互,上传签名文件。
  • BottomClock:自定义组件,用于提供底部的操作按钮(重写和确认)。

安装依赖

安装所需的依赖库:

npm install react-signature-canvas antd-mobile @minio-js/minio
  • react-signature-canvas:用于绘制签名。
  • @minio-js/minio:用于与 MinIO 服务器进行文件上传。

创建签名组件

引入 SignatureCanvas

react-signature-canvas 是一个非常方便的 React 组件,它提供了画布绘制的功能。我们可以通过 ref 来控制画布的行为,例如清除签名、获取签名数据等。

import React, { useRef } from "react";
import SignatureCanvas from "react-signature-canvas";const sigCanvas = useRef();// 清除签名
const clearSignature = () => {if (sigCanvas.current) {sigCanvas.current.clear();}
};// 获取签名的 Base64 数据
const getSignatureData = () => {if (sigCanvas.current) {return sigCanvas.current.toDataURL();}return null;
};
将 Base64 转换为文件流

签名数据是以 Base64 格式返回的,为了将其上传到服务器,我们需要将其转换为文件流。我们可以编写一个辅助函数 dataURLtoFile 来完成这个任务:

const dataURLtoFile = (base64, fileName) => {const data = base64.split(",");const type = data[0].match(/:(.*?);/)[1];const suffix = type.split("/")[1];const bstr = window.atob(data[1]);let n = bstr.length;const u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}return new File([u8arr], `${fileName}.${suffix}`, { type: type });
};
保存签名并上传
import { uploadFileFun } from "@/utils/minio.js";
import { Toast } from "antd-mobile";const saveSignature = async () => {const isEmpty = sigCanvas.current.isEmpty(); // 检查是否为空if (!isEmpty && sigCanvas.current) {const dataUrl = sigCanvas.current.toDataURL(); // 获取签名的 Base64 数据try {const file = dataURLtoFile(dataUrl, "signature");const response = await uploadFileFun(file); // 上传文件到 MinIOconsole.log("签名已成功上传:", response);props.saveSignature(response); // 将上传结果传递给父组件} catch (error) {console.error("上传失败:", error);Toast.show({content: "签名上传失败,请稍后再试。",});}} else {Toast.show({content: "请先完成签名。",});}
};

完整的签名组件代码

import React, { useRef } from "react";
import SignatureCanvas from "react-signature-canvas";
import BottomClock from "@/components/BottomClick/index";
import { Toast } from "antd-mobile";
import { uploadFileFun } from "@/utils/minio.js";export default function Signature(props) {const sigCanvas = useRef();// 清除签名const clearSignature = () => {if (sigCanvas.current) {sigCanvas.current.clear();}};// Base64格式转文件流const dataURLtoFile = (base64, fileName) => {const data = base64.split(",");const type = data[0].match(/:(.*?);/)[1];const suffix = type.split("/")[1];const bstr = window.atob(data[1]);let n = bstr.length;const u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}return new File([u8arr], `${fileName}.${suffix}`, { type: type });};// 保存签名const saveSignature = async () => {const isEmpty = sigCanvas.current.isEmpty(); // 检查是否为空if (!isEmpty && sigCanvas.current) {const dataUrl = sigCanvas.current.toDataURL(); // 获取签名的 Base64 数据try {const file = dataURLtoFile(dataUrl, "signature");const response = await uploadFileFun(file); // 上传文件到 MinIOconsole.log("签名已成功上传:", response);props.saveSignature(response); // 将上传结果传递给父组件} catch (error) {console.error("上传失败:", error);Toast.show({content: "签名上传失败,请稍后再试。",});}} else {Toast.show({content: "请先完成签名。",});}};return (<div className="signaturecontainer"><SignatureCanvaspenColor="#0000ff" // 设置画笔颜色为蓝色maxWidth={6}canvasProps={{className: "sigCanvas",}}ref={sigCanvas}/><div className="button-container"><BottomClockreset={"重写"}confirm={"确认"}onReset={clearSignature}onSubmit={saveSignature}/></div></div>);
}

文件上传到 MinIO

配置 MinIO

MinIO 是一个高性能的对象存储系统,适合用于存储文件。我们可以通过 minio.js 库与 MinIO 服务器进行交互。首先,确保你已经安装并配置了 MinIO 服务器,并且有一个可用的存储桶。

编写上传函数

@/utils/minio.js 中编写一个上传文件的函数 uploadFileFun,该函数将接收文件对象并将其上传到 MinIO 服务器:

import { Client, S3Error } from "@minio-js/minio";const minioClient = new Client({endPoint: "your-minio-endpoint", // 替换为你的 MinIO 服务器地址port: 9000, // 替换为你的 MinIO 服务器端口useSSL: false, // 是否使用 HTTPSaccessKey: "your-access-key", // 替换为你的 MinIO 访问密钥secretKey: "your-secret-key", // 替换为你的 MinIO 秘钥
});export const uploadFileFun = async (file) => {try {const bucketName = "signatures"; // 存储桶名称const objectName = file.name; // 文件名const metaData = {"Content-Type": file.type,};// 上传文件到 MinIOawait minioClient.putObject(bucketName, objectName, file, metaData);// 获取文件的 URLconst url = await minioClient.presignedGetObject(bucketName, objectName, 60 * 60 * 24); // 签名链接有效期为 24 小时return url;} catch (err) {if (err instanceof S3Error) {console.error("MinIO 错误:", err);} else {console.error("未知错误:", err);}throw err;}
};

参考资料

  • React Signature Canvas
  • MinIO JavaScript SDK
  • Ant Design Mobile

http://www.ppmy.cn/ops/143392.html

相关文章

9_less教程 --[CSS预处理]

LESS&#xff08;Leaner Style Sheets&#xff09;是一种CSS预处理器&#xff0c;它扩展了CSS语言&#xff0c;增加了变量、嵌套规则、混合&#xff08;mixins&#xff09;、函数等功能&#xff0c;使得样式表的编写更加灵活和易于维护。下面是一些LESS的基础教程内容&#xff…

docker 容器相互访问

目前采用 network 方式 1. 创建自定义网络 docker network create network-group 如下 2. 相互访问的容器更改&#xff08;目前演示redis 以及netcore api 访问redis &#xff09; //redis 原有容器删除 跟之前区别就是加入 --network network-group docker run \ -p 6379:…

zookeeper基础命令详解

zookeeper基础命令详解目录 文章目录 zookeeper基础命令详解目录一、列出所有基础命令 一、列出所有基础命令 先启动一个zookeeper客户端连接zookeeper&#xff0c;如果还没有启动zookeeper集群的参考本文启动之后再做后续操作。 https://blog.csdn.net/weixin_42924400/artic…

.Net Core配置使用Log4Net日志记录

在NuGet包管理中&#xff0c;搜索 Microsoft.Extensions.Logging.Log4Net.AspNetCore 在Startup.cs类中添加如下代码 //添加Log4Net var path Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config"); //不带参数&#xff1a;表示log4net.config…

已有 containerd 的情况下部署二进制 docker 共存

文章目录 [toc]学习目的开始学习dockerd启动 containerd准备配置文件启动 containerd 启动 docker准备配置文件启动 docker 环境验证停止 docker 和 containerd 学习目的 使用容器的方式做一些部署的交付&#xff0c;相对方便很多&#xff0c;不需要担心别人的环境缺少需要的依…

(耗时4天制作)详细介绍macOS系统 本博文含有全英版

下面为大家详细介绍macOS系统介绍&#xff1a; 一、macOS系统概述 macOS是由苹果公司开发的专有操作系统&#xff0c;主要用于Macintosh&#xff08;Mac&#xff09;系列计算机。它是首个在商用领域成功的图形用户界面&#xff08;GUI&#xff09;操作系统&#xff0c;自诞生…

第十五章 Linux Shell 编程

15.1 Shell 变量 了解&#xff1a;Shell的功能 了解&#xff1a;Shell的种类 了解&#xff1a;Shell的调用 了解&#xff1a;Shell变量的概念 了解&#xff1a;Shell变量的定义 了解&#xff1a;Shell数组变量 了解&#xff1a;Shell内置变量 了解&#xff1a;双引号 和…

力扣题目 - 3264.K 次乘运算后的最终数组I

题目 还需要你前往力扣官网查看详细的题目要求 地址 1.给你一个整数数组 nums &#xff0c;一个整数 k 和一个整数 multiplier 。2.你需要对 nums 执行 k 次操作&#xff0c;每次操作中&#xff1a;找到 nums 中的 最小 值 x &#xff0c;如果存在多个最小值&#xff0c;选择最…