React PDF缩放时,Viewport Scale是否需与Page Scale同步?
问题
我在React项目中使用封装了pdf.js的react-pdf组件展示PDF文件,目前通过如下代码设置scale实现PDF的放大与缩小:
<Page key={index + "@new-" + projAttribute.pdfScale} scale={projAttribute.pdfScale} className={styles.pdfPage} onLoad={handlePageChange} canvasRef={(element) => updateRefArray(index, element)} onChange={handlePageChange} onRenderSuccess={handlePageRenderSuccess} pageNumber={index} width={width} > {curPdfPosition && viewPort ? ( <Highlight position={curPdfPosition} pageNumber={index} viewport={viewPort} ></Highlight> ) : ( <div></div> )} </Page>
同时通过以下代码获取viewport:
React.useEffect(() => { setPageViewports(undefined); if (!pdf) { return; } (async () => { const pageNumbers = Array.from(new Array(pdf.numPages)).map( (_, index) => index + 1 ); const nextPageViewports = await asyncMap( pageNumbers, (pageNumber: number) => pdf .getPage(pageNumber) .then((page) => page.getViewport({ scale: projAttr.pdfScale || 1 }) ) ); setPageViewports(nextPageViewports); })(); }, [pdf]);
我的PDF缩放范围为0.1-6.0,每次点击缩放按钮增减0.1。请问在此场景下,是否需要同步修改viewport的scale,使其与PDF的scale保持一致?或者viewport的scale应设置为其他值?
回答
必须同步修改viewport的scale,让它和<Page>组件的scale值保持一致,核心原因如下:
- 高亮定位精准性:你使用的
<Highlight>组件依赖viewport来计算高亮区域的像素坐标。如果viewport的scale与PDF显示的scale不匹配,高亮会出现偏移,无法准确对应到PDF页面上的目标位置。 - 坐标映射一致性:pdf.js的viewport负责将PDF原生的72DPI坐标转换为页面显示的像素坐标。只有当viewport的scale和
<Page>的scale完全一致时,所有基于坐标的操作(比如高亮、批注、点击定位)才能和视觉显示完全匹配。 - 当前代码的缺陷:你的useEffect仅监听
pdf的变化,未监听projAttr.pdfScale。这意味着用户点击缩放按钮修改pdfScale时,viewport不会更新,会直接导致后续高亮等操作失效或错位。
修正方案
将projAttr.pdfScale加入useEffect的依赖数组,确保每次缩放值变化时,重新计算对应scale的viewport:
React.useEffect(() => { setPageViewports(undefined); if (!pdf) { return; } (async () => { const pageNumbers = Array.from(new Array(pdf.numPages)).map( (_, index) => index + 1 ); const nextPageViewports = await asyncMap( pageNumbers, (pageNumber: number) => pdf .getPage(pageNumber) .then((page) => page.getViewport({ scale: projAttr.pdfScale || 1 }) ) ); setPageViewports(nextPageViewports); })(); }, [pdf, projAttr.pdfScale]); // 新增pdfScale到依赖列表
另外,建议在<Page>的onRenderSuccess回调中也获取当前页面的viewport,作为兜底方案,避免异步加载导致的viewport与显示scale不同步问题。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

