react-signature-canvas在Ant Design Modal中无法生成Base64图像问题
问题:React SignaturePad 嵌入 Ant Design Modal 无法生成有效 Base64 签名图像
将 SignaturePad 组件嵌入 Ant Design 的 Modal 组件中时,调用trim函数获取签名的 Base64 内容,返回值仅为"data:";移除 Modal 标签后,能正常返回完整的"data:image/png;base64,iVBORw0KGgoxxxxx...."格式内容,怀疑是签名库与 Ant Design Modal 的兼容问题。
相关代码
父组件 FormComponent
import { Form, Modal } from 'antd'; const FormComponent = () => { const [form] = Form.useForm(); return ( <Modal title="Signature Form" open={true}> <div> <Form form={form} > <div> <SignaturePad name="signature" title="Signature" setFieldValue={(fieldName, value) => { formSign.setFieldsValue({ [fieldName]: value }); }} status={undefined} skipValidation={false} /> </div> </Form> </div> </Modal> ); };
自定义 SignaturePad 组件
import React, { useRef, RefObject } from 'react'; import SignaturePad from 'react-signature-canvas'; import { Button, Form } from 'antd'; interface SignaturePadProps { name: string; title: string; setFieldValue: (fieldName: string, value: any) => void; status?: 'error' | 'success'; skipValidation?: boolean; } const SignaturePad: React.FC<SignaturePadProps> = ({ name, title, setFieldValue, status, skipValidation, }) => { const ref: RefObject<SignaturePad> = useRef<SignaturePad>(null); const isErrorBorder = status === 'error' ? 'signing-error-border' : ''; const trim = () => { if (ref.current) { let sign = ref.current.toDataURL('image/png'); setFieldValue(name, sign); } }; const clear = () => { if (ref.current) { ref.current.clear(); setFieldValue(name, ''); } }; return ( <Form.Item {...{ labelCol: { span: 4, } }} label={title} name={name} rules={[{ required: !skipValidation, message: 'This field is required' }]} valuePropName="data-url" > <section className='sign_form'> <SignaturePad onEnd={trim} canvasProps={{ className: `sign_canvas ${isErrorBorder}`, }} ref={ref} /> <Button onClick={clear} className='clear-btn'> Clear </Button> </section> </Form.Item> ); }; export default SignaturePad;
问题分析与解决方案
这不是直接的库兼容问题,核心原因是 Modal 初始化时,内部 Canvas 元素未完成尺寸渲染,导致toDataURL无法捕获有效画布内容。Ant Design Modal 默认是懒渲染机制,即使设置open={true},组件也会异步完成挂载,此时 Canvas 宽高可能为0,调用toDataURL就会返回空的data:字符串。
方案1:监听 Modal 渲染完成事件,延迟加载 SignaturePad
利用 Modal 的afterOpen回调,确保 Modal 完全渲染后再挂载 SignaturePad:
import { Form, Modal } from 'antd'; import { useState } from 'react'; const FormComponent = () => { const [form] = Form.useForm(); const [modalReady, setModalReady] = useState(false); return ( <Modal title="Signature Form" open={true} afterOpen={() => setModalReady(true)}> <div> <Form form={form}> {modalReady && ( <div> <SignaturePad name="signature" title="Signature" setFieldValue={(fieldName, value) => { form.setFieldsValue({ [fieldName]: value }); }} status={undefined} skipValidation={false} /> </div> )} </Form> </div> </Modal> ); };
方案2:为 Canvas 设置固定尺寸
在自定义 SignaturePad 组件中,给 Canvas 明确指定宽高,避免 Modal 渲染时尺寸异常:
<SignaturePad onEnd={trim} canvasProps={{ className: `sign_canvas ${isErrorBorder}`, width: 500, height: 200 }} ref={ref} />
方案3:在trim函数中检查并修正 Canvas 尺寸
在生成 Base64 前,确保 Canvas 有有效尺寸:
const trim = () => { if (ref.current) { const canvas = ref.current.getCanvas(); // 若画布尺寸为0,设置默认值 if (canvas.width === 0 || canvas.height === 0) { canvas.width = 500; canvas.height = 200; } let sign = ref.current.toDataURL('image/png'); setFieldValue(name, sign); } };
额外修正点
原父组件代码中formSign未定义,应改为form(方案1中已修正)。
内容的提问来源于stack exchange,提问作者Jing c
相关产品推荐
相关产品推荐

