关于js实现手写签名

原有的业务逻辑是用户线下签字,然后拍照后将照片上传到后台系统。用户将手机端照片转移到电脑也很复杂。特别是对于非自己的电脑的图片上传。所以将业务转到ipad或者surface上,减少操作逻辑。

1. 实现操作逻辑

这个直接参考MDN的触摸事件的文档。里面提供了完整的代码。

将其整理成React组件形式如下:

js 复制代码
import React, { useEffect, forwardRef, useImperativeHandle, useState } from 'react';

const Signature: React.FC = (props, ref) => {
    const color = "#000";
    useImperativeHandle(ref, () => ({
        getImage: () => new Promise((resolve,reject) => {
            // 返回处理后的数据形式
        })
    }));

    useEffect(() => {
        const el = document.querySelector("#signCanvas");
        el?.addEventListener("touchstart", handleStart, false);
        el?.addEventListener("touchend", handleEnd, false);
        el?.addEventListener("touchmove", handleMove, false);
    }, [])
    
    // 所有方法参考MDN内的实现方法
    const ongoingTouches = [];
    function copyTouch(touch) {}
    function ongoingTouchIndexById(idToFind) { }
    function handleStart(evt) {}
    function handleMove(evt) {}
    function handleEnd(evt) {}
  return (
        <canvas id="signCanvas" width="600" height="600" style={{border: "solid #aaa 1px"}}>
          你的浏览器不支持 canvas 元素。
        </canvas>
  );
};

export default forwardRef(Signature);

2. 注意细节

1. 获取canvas元素

ini 复制代码
// MDN中获取元素的类型
const el = document.getElementsByTagName("canvas")[0];

如果代码中已经有了canvas元素,比如antd中使用的QrCode组件。

2. 坐标设置(无滚动条)

MDN中的demo使用的pageX和pageY默认使用的是屏幕左上角,我使用的时候用的是弹窗打开,弹窗位于页面中间。 此时应该基于弹窗的位置进行设置。

为啥是top*2?试出来的,我也不知道

js 复制代码
// 在start方法中挪动坐标位置
    function handleStart(evt) {
        evt.preventDefault();
        const el = document.querySelector("#signCanvas");
        const ctx = el?.getContext("2d");
        const { left, top } = el?.getBoundingClientRect();
        ctx?.translate(0 - left, 0 - top*2);
        .......
     }
// 每次画完再把坐标复原,不然,坐标每画一次挪一次,就越来越远了。
    function handleEnd(evt) {
        evt.preventDefault();
        const el = document.querySelector("#signCanvas");
        const ctx = el?.getContext("2d");       
        const { left, top } = el?.getBoundingClientRect();
        ctx?.translate(0 + left, 0 + top*2);  
        ......
    }

3. 坐标取值(有滚动条)

当弹窗下的页面出现滚动条时,pageX,pageY会把滚动条计算进去。此时要改成screenX,screenY

4. 将签名转图片保存

1. 转base64图片

js 复制代码
            const el = document.querySelector("#signCanvas");
            el?.toBlob((blob) => {
                var reader = new FileReader();
                reader.readAsDataURL(blob); 
                reader.onloadend = function() {
                  var base64data = reader.result;   
                  resolve(base64data)        
                }
            },  "image/png")

2. 转file类型

js 复制代码
// 解析文件
export const base64ToFile = (dataurl) => {
  const arr = dataurl.split(',');
  const mime = arr[0].match(/:(.*?);/)[1];
  const bstr = window.atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  let blob = new File([u8arr], 'file.png', { type: mime });
  return blob; 
};

// 将base64转为file
  const file = base64ToFile(base64data);   

5. 兼容性

用到了Touch事件,不支持safari浏览器

相关推荐
前端小菜袅13 分钟前
uniapp配置自动导入uni生命周期等方法
前端·javascript·uni-app
Apifox14 分钟前
如何在 Apifox 中通过 AI 一键生成几十个测试用例?
前端·后端·ai编程
你真的可爱呀15 分钟前
uniapp学习【整体实践】
前端·学习·uni-app·实践
一枚前端小能手22 分钟前
「周更第7期」实用JS库推荐:Vite
前端·javascript·vite
小中123438 分钟前
异步请求的性能提升
前端
我是天龙_绍40 分钟前
渐变层生成器——直接用鼠标拖拽就可以调整渐变层的各种参数,然后可以导出为svg格式
前端
我是天龙_绍1 小时前
Easing 曲线 easings.net
前端
知识分享小能手1 小时前
微信小程序入门学习教程,从入门到精通,电影之家小程序项目知识点详解 (17)
前端·javascript·学习·微信小程序·小程序·前端框架·vue
訾博ZiBo1 小时前
React组件复用导致的闪烁问题及通用解决方案
前端
Dever1 小时前
记一次 CORS 深水坑:开启 withCredentials 后Response headers 只剩 content-type
前端·javascript