如何将DocuSign集成到React应用并实现PDF签名区域拖拽定位功能?
React 实现PDF拖拽签名区域并捕获坐标方案
我之前做过类似需求,核心思路是用react-pdf渲染PDF,结合拖拽库(或原生拖拽事件)实现签名区域的位置调整,最后将页面像素坐标转换为PDF原生坐标并记录页码。以下是完整可落地的方案:
核心依赖
先安装必要依赖:
npm install react-pdf react-dnd react-dnd-html5-backend
完整代码实现
1. 可拖拽签名区域组件
import { useDrag } from 'react-dnd'; const SignatureArea = ({ onPositionChange, pageNumber }) => { const [{ isDragging }, dragRef] = useDrag({ type: 'SIGNATURE', collect: (monitor) => ({ isDragging: monitor.isDragging(), }), end: (_, monitor) => { const dropResult = monitor.getDropResult(); if (!dropResult?.pageRef) return; // 获取PDF页面的渲染区域信息 const pageElement = dropResult.pageRef.current; const pageRect = pageElement.getBoundingClientRect(); const mousePos = monitor.getClientOffset(); // 转换为PDF原生坐标(PDF默认72DPI,宽度612px) const pdfOriginalWidth = 612; const scaleRatio = pdfOriginalWidth / pageRect.width; const finalPos = { x: Math.round((mousePos.x - pageRect.left) * scaleRatio), y: Math.round((mousePos.y - pageRect.top) * scaleRatio), page: pageNumber }; onPositionChange(finalPos); }, }); return ( <div ref={dragRef} style={{ position: 'absolute', width: '100px', height: '50px', border: '2px dashed #2196F3', backgroundColor: isDragging ? 'rgba(33,150,243,0.2)' : 'transparent', cursor: 'move', top: '20px', left: '20px' }} /> ); };
2. PDF页面拖拽容器
import { useRef } from 'react'; import { Page } from 'react-pdf'; import { useDrop } from 'react-dnd'; const PDFPageContainer = ({ pageNumber, onSignatureDrop, children }) => { const pageRef = useRef(null); const [{ isOver }, dropRef] = useDrop({ accept: 'SIGNATURE', collect: (monitor) => ({ isOver: monitor.isOver(), }), drop: () => ({ pageRef }) }); return ( <div ref={dropRef} style={{ position: 'relative', margin: '20px auto', maxWidth: '800px', border: isOver ? '2px solid #4CAF50' : 'none' }} > <Page ref={pageRef} pageNumber={pageNumber} renderTextLayer={false} renderAnnotationLayer={false} width={800} /> {children} </div> ); };
3. 主应用组件
import { useState } from 'react'; import { Document } from 'react-pdf'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import PDFPageContainer from './PDFPageContainer'; import SignatureArea from './SignatureArea'; const PDFSignatureApp = () => { const [pdfUrl, setPdfUrl] = useState(null); const [totalPages, setTotalPages] = useState(0); const [signaturePos, setSignaturePos] = useState(null); const handleFileUpload = (e) => { const file = e.target.files[0]; if (file) setPdfUrl(URL.createObjectURL(file)); }; const handleDocLoad = ({ numPages }) => setTotalPages(numPages); return ( <div style={{ padding: '20px' }}> <input type="file" accept=".pdf" onChange={handleFileUpload} /> {pdfUrl && ( <DndProvider backend={HTML5Backend}> <Document file={pdfUrl} onLoadSuccess={handleDocLoad}> {Array.from({ length: totalPages }, (_, idx) => ( <PDFPageContainer key={idx + 1} pageNumber={idx + 1}> <SignatureArea pageNumber={idx + 1} onPositionChange={setSignaturePos} /> </PDFPageContainer> ))} </Document> </DndProvider> )} {signaturePos && ( <div style={{ marginTop: '20px', padding: '10px', backgroundColor: '#f5f5f5' }}> <h4>签名区域坐标:</h4> <pre>{JSON.stringify(signaturePos, null, 2)}</pre> </div> )} </div> ); }; export default PDFSignatureApp;
关键注意事项
- 坐标转换逻辑:PDF默认采用72DPI的坐标系统,宽度为612px(8.5英寸),如果你的PDF是自定义尺寸,需要通过
Page组件的onLoadSuccess事件获取页面原始尺寸,替换代码中的pdfOriginalWidth。 - 多签名支持:如果需要添加多个签名区域,只需将
signaturePos改为数组类型,在onPositionChange中追加坐标对象即可。 - 原生拖拽替代:如果不想用
react-dnd,可以通过原生的dragstart、dragover、drop事件实现,核心逻辑都是在拖拽结束时计算相对页面的坐标并转换为PDF原生坐标。
内容的提问来源于stack exchange,提问作者shin98
相关产品推荐
相关产品推荐

