• canvas 签名组件封装


    可设置canvas的width、height属性动态设置画布大小,不要通过css设置画布的宽高,不然可能导致画布变形

    import React, { useRef, useEffect } from "react";
    import "./index.less";
    
    /*
     *  签名组件
      @params width 画布宽度
      @params height 画布高度
      @params fillStyle 绘制图形的填充色
      @params strokeStyle 绘制图形的描边色
      @params lineWidth 线宽
      @params lineCap 线条末端样式
      @params lineJoin 线条间连接样式
     */
    export default function Signature(props) {
      const {
        width = 300,
        height = 150,
        fillStyle = "#fff",
        strokeStyle = "#000",
        lineWidth = 1,
        lineCap = "butt",
        lineJoin = "miter",
        onChange = () => {}
      } = props;
      const canvasRef = useRef(); // canvas
      const ctxRef = useRef(); // canvas的2d上下文
    
      useEffect(() => {
        const init = () => {
          let moveing = false;
          const canvas = canvasRef.current;
          const ctx = canvas.getContext("2d");
          ctxRef.current = ctx;
          canvas.addEventListener("mousedown", (e) => {
            if (!moveing) {
              ctx.moveTo(e.offsetX, e.offsetY);
              moveing = true;
            }
          });
          canvas.addEventListener(
            "mousemove",
            (e) => {
              if (moveing) {
                ctx.lineTo(e.offsetX, e.offsetY);
                ctx.fillStyle = fillStyle;
                ctx.strokeStyle = strokeStyle;
                ctx.lineWidth = lineWidth < 1 ? 1 : lineWidth;
                ctx.lineCap = lineCap;
                ctx.lineJoin = lineJoin;
                ctx.stroke();
              }
            },
            false
          );
          canvas.addEventListener(
            "mouseup",
            () => {
              moveing = false;
              // 将canvas转换成base64的url
              const url = canvas.toDataURL("signature/png");
              onChange(url);
            },
            false
          );
          canvas.addEventListener(
            "mouseleave",
            () => {
              moveing = false;
            },
            false
          );
        };
        init();
      }, []);
    
      // 清除画布
      const onClearHandler = () => {
        const ctx = ctxRef.current;
        ctx.clearRect(0, 0, width, height);
        ctx.beginPath();
        onChange("");
      };
    
      return (
        <div className="signatureWrapper">
          <canvas className="signatureBox" ref={canvasRef} width={width} height={height}>
            Your browser not support!
          </canvas>
          <span className="signature-clear" onClick={() => onClearHandler()}>
            CLEAR
          </span>
        </div>
      );
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    .signatureWrapper {
      position: relative;
      width: fit-content;
      .signatureBox {
        box-shadow: 0 1px 8px rgb(0, 0, 0, 0.3);
      }
      .signature-clear {
        position: absolute;
        right: 30px;
        bottom: 10px;
        padding: 2px 8px;
        cursor: pointer;
        color: red;
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    HTML5 参考手册
    学习 HTML5 Canvas 这一篇文章就够了

  • 相关阅读:
    python 实现贪心算法
    公众号题库搜题对接
    [SpringBoot系列]SpringBoot如何整合SSMP
    MySQL服务复制
    static_cast, dynamic_cast与reinterpret_cast的区别
    嵌入式Linux应用开发基础知识(三)——Makefile入门
    2022-09-28 Android APP 用interface 接口的形式对jni进行回调,实例测试
    一条龙-T检验+绘制boxplot
    LLM推理的极限速度
    LeetCode——动态规划篇(一)
  • 原文地址:https://blog.csdn.net/qq_32247819/article/details/128144643