react-to-print打印PDF时无法单独调整二维码尺寸问题
问题背景
网站开发中使用react-qr-code生成二维码,使用react-to-print实现二维码导出PDF打印功能。核心需求为在不改变React页面上二维码原有显示尺寸的前提下,单独调整导出PDF文件内的二维码大小。
此前尝试通过state状态修改QRCode组件的size属性,但状态更新会同步修改DOM容器内页面展示的二维码尺寸,无法实现打印尺寸与页面显示尺寸的独立控制,原有问题代码如下:
import QRCode from 'react-qr-code'; import ReactToPrint from 'react-to-print'; const getPageMargins = () => { return `@page { margin: '1000px' '10' '10 '10' !important; }`; }; const onBeforeGetContent = () => { setSize(200); setIsLoading(true); return Promise.resolve(); }; const onBeforePrint = () => { setSize(100); return Promise.resolve(); }; const onAfterPrint = () => { setSize(100); setIsLoading(true); return Promise.resolve(); }; // 渲染部分 <div ref={QRRef}> <QRCode value={`{ "_id": "${unit.id}" }`} size={size} /> <p className="hide-unit-id">{unit.id}</p> </div> <ReactToPrint pageStyle={getPageMargins} onBeforePrint={onBeforePrint} onBeforeGetContent={onBeforeGetContent} onAfterPrint={onAfterPrint} trigger={() => ( <PrinterFilled /> )} content={() => QRRef.current}> </ReactToPrint>
解决方案
最稳定的实现方式是使用打印专属CSS媒体查询,完全不需要动态修改组件state,不会触发页面重渲染,也不会导致页面上的二维码尺寸跳变,天然实现显示尺寸和打印尺寸的隔离。
具体实现步骤:
- 移除所有动态修改二维码size的state逻辑,删除
onBeforeGetContent、onBeforePrint、onAfterPrint中修改size、loading状态的代码,页面上二维码的size属性固定为页面展示需要的尺寸即可,全程不需要改动这个值。 - 新增打印专属CSS样式,利用
@media print媒体查询,仅在触发打印/导出PDF时生效,给二维码设置需要的打印尺寸。注意react-qr-code渲染输出为SVG标签,内联样式优先级高,需要加!important覆盖默认宽高。 - 修正原有
getPageMargins方法的语法错误:原代码margin属性值多了多余的单引号,部分数值缺失单位。
实现代码
首先添加打印样式,可放在全局CSS或组件对应的CSS文件中:
@media print { /* 仅打印时生效,完全不影响页面正常显示 */ .print-qr-container svg { width: 200px !important; height: 200px !important; } /* 不需要打印的元素可在此处设置隐藏,比如示例中的unit_id文本如果不需要出现在PDF里可打开下面的注释 */ /* .hide-unit-id { display: none !important; } */ }
调整后的组件代码:
import QRCode from 'react-qr-code'; import ReactToPrint from 'react-to-print'; import { PrinterFilled } from '@ant-design/icons'; import { useRef } from 'react'; const QrPrintComponent = ({ unit }) => { const QRRef = useRef(null); // 固定页面显示的二维码尺寸,不需要用state管理 const pageDisplayQrSize = 100; // 修正后的打印页边距配置,按实际需求调整数值即可 const getPageMargins = () => { return `@page { margin: 10mm !important; }`; }; return ( <> <div ref={QRRef} className="print-qr-container"> <QRCode value={`{ "_id": "${unit.id}" }`} size={pageDisplayQrSize} /> <p className="hide-unit-id">{unit.id}</p> </div> <ReactToPrint pageStyle={getPageMargins} trigger={() => <PrinterFilled style={{ cursor: 'pointer' }} />} content={() => QRRef.current} /> </> ); }; export default QrPrintComponent;
方案优势
- 无页面跳变:全程不修改组件state,不会触发页面重渲染,用户操作时看不到页面上的二维码尺寸变化,体验流畅。
- 维护简单:打印样式和页面展示样式完全隔离,后续调整尺寸只需要改对应CSS值即可,不需要处理复杂的回调时序问题。
- 兼容性好:
@media print是浏览器原生支持的标准特性,和react-to-print适配无兼容问题。
内容的提问来源于stack exchange,提问作者Drashti Kheni
相关产品推荐
相关产品推荐

