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);
}
}
}
}
}
}
网友评论