React 橫屏簽名

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()}
              >
                確認(rèn)
              </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頁面翻轉(zhuǎn)
  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);
  //將簽名還原翻轉(zhuǎn),就可以保證在橫屏情況下保證畫筆的方向跟手勢一致,然后再進(jìn)行高度和寬度的調(diào)整。
  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);
          }
        }
      }
    }
  }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容