美文网首页
React 横屏签名

React 横屏签名

作者: 清霆 | 来源:发表于2024-07-09 10:49 被阅读0次
import clsx from 'clsx';
import { useEffect, useRef, useState } from 'react';
import type { CSSProperties } from 'react';
import { Popup } from 'react-vant'; // 不推荐使用移动端特色组件库
import SignatureCanvas from 'react-signature-canvas';

interface Props {
  open: boolean;
  onOpenChange: (value?: boolean) => void;
  onChange: (value?: string) => void;
}
export default function Sign({ open, onOpenChange, onChange }: Props) {
  const signCanvas = useRef<SignatureCanvas>(null);
  const [signVisible, setSignVisible] = useState(false);

  useEffect(() => {
    setSignVisible(open);
  }, [open]);

  const confirm = () => {
    const sign = signCanvas.current!.toDataURL('image/png')!;
    onChange(sign);
    onOpenChange(false);
  };

  return (
    <Popup
      className={'sign-contracted-modal'}
      visible={signVisible}
      onClose={() => setSignVisible(false)}
      position="top"
      onOpen={() => {
        detectOrient(signCanvas.current!);
      }}
    >
      <div className={'sign-contracted'} id="sign-contracted">
        <div id="sign-content" className={'sign-content'}>
          <SignatureCanvas
            ref={signCanvas}
            penColor="black"
            backgroundColor="#F5F5F5"
            canvasProps={{
              width: 200,
              height: 200,
              className: 'signCanvas',
            }}
          />
          <div className={'sign-bar'}>
            <div className={'actions'}>
              <div
                className={'btn'}
                onClick={() => {
                  signCanvas.current?.clear();
                }}
              >
                清除
              </div>
              <div
                className={clsx(['btn', 'submit'])}
                onClick={() => confirm()}
              >
                确认
              </div>
            </div>
          </div>
        </div>
      </div>
    </Popup>
  );
}

function detectOrient(
  signCanvas?: SignatureCanvas,
  backgroundColor = 'transparent',
) {
  if (!signCanvas) {
    return;
  }
  const width = document.documentElement.clientWidth;
  const height = document.documentElement.clientHeight;
  if (width >= height) {
    return;
  }
  //将整个h5页面翻转
  const $wrapper = document.getElementById('sign-contracted')!;
  if (!$wrapper) {
    return;
  }
  const style: CSSProperties = {
    width: `${height}px`,
    height: `${width}px`,
    transform: `rotate(90deg)`,
    transformOrigin: `${width / 2}px ${width / 2}px`,
    // '-webkit-transform':`rotate(90deg)`,
    // '-webkit-transform-origin':`${width / 2}px ${width / 2}px`,
  };

  $wrapper.style.cssText = js2Css(style);
  //将签名还原翻转,就可以保证在横屏情况下保证画笔的方向跟手势一致,然后再进行高度和宽度的调整。
  const parentElement = document.getElementById('sign-content')!;
  const pw = parentElement.clientWidth;
  const ph = parentElement.clientHeight;
  parentElement.style.cssText = `height: ${ph}px;`;
  const canvasElement = signCanvas.getCanvas();
  canvasElement.height = pw;
  canvasElement.width = ph;

  const canvasStyle: CSSProperties = {
    backgroundColor,
    transform: `rotate(-90deg)`,
    transformOrigin: `${ph / 2}px ${ph / 2}px`,
    // '-webkit-transform':`rotate(-90deg)`,
    // '-webkit-transform-origin':`${ph / 2}px ${ph / 2}px`,
  };
  canvasElement.style.cssText = js2Css(canvasStyle);
}

function js2Css(styleObj: CSSProperties) {
  if (typeof styleObj === 'string') {
    return styleObj;
  }
  return Object.entries(styleObj)
    .filter((item) => item[1] !== undefined && item[1] !== null)
    .map(([property, value]) => `${property}:${value};`)
    .join(' ');
}
.sign-contracted-modal {
  width: 100%;
  height: 100%;
  .sign-contracted {
    width: 100%;
    height: 100%;
    .sign-content {
      width: 100%;
      height: 100%;
      position: relative;
      .sign-bar {
        width: 100%;
        height: fit-content;
        padding: 0 32px 12px 32px;
        position: absolute;
        left: 0;
        bottom: 0;
        z-index: 10;
        display: flex;
        justify-content: space-between;
        align-items: center;
        .actions {
          display: flex;
          align-items: center;
          gap: 12px;
        }
        .btn {
          width: 108px;
          height: 36px;
          border-radius: 6px;

          font-weight: 500;
          font-size: 16px;
          color: #1c64d7;
          border: 1px solid #1c64d7;
          background: #fff;

          display: flex;
          justify-content: center;
          align-items: center;
          &.submit {
            background: #1c64d7;
            color: rgba(255, 255, 255, 0.95);
          }
        }
      }
    }
  }
}

相关文章

网友评论

      本文标题:React 横屏签名

      本文链接:https://www.haomeiwen.com/subject/qtaacjtx.html