React PDF渲染:如何实现每页最多9个、每行3个二维码?
问题
我正在开发一个生成含二维码列表的PDF的React函数,因二维码数量可能较多,希望实现每页最多显示9个二维码,且每行固定显示3个。我尝试了以下代码,但未达到预期效果,请问后续该如何调整?
function QrCodePDF(props: QrCodeInfo[]) { const qrCodeInfo = props; const qrCodeItems: QrCodeInfo[] = []; for (let index in qrCodeInfo) { qrCodeItems.push({ dealTitle: qrCodeInfo[index]!.dealTitle, qrCodeId: qrCodeInfo[index]!.qrCodeId, qrCodeUrl: qrCodeInfo[index]!.qrCodeUrl, }); } return ( <Document> <Page size="A4" style={{ flexDirection: 'column', backgroundColor: '#fff', color: '#000', padding: 10, }} wrap={true} > <View style={{ flex: 1, width: '100%', border: '1px solid #000', }} key={'QrCodeTable'} > <View style={{ display: 'flex', width: '100%', fontWeight: 'bold', fontSize: '20px', textAlign: 'center', flexDirection: 'row', alignItems: 'center', borderBottom: '1px solid #000', }} > <Text style={{ width: '100%', padding: 10, }} > Qr Code for {qrCodeItems[0]?.dealTitle} </Text> </View> <View style={{ display: 'flex', flexWrap: 'wrap', flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }} key={'QrCodeWrapper'} > {qrCodeItems.map((item, index) => { return ( <View key={index} style={{ width: '33.33%', alignItems: 'center', flexDirection: 'row', fontWeight: 'normal', fontSize: '14px', textAlign: 'left', color: '#000', flexWrap: 'wrap', gap: 0, }} break={index > 3} wrap={true} > <Image src={item.qrCodeUrl} style={{ width: '100%', padding: 10 }} ></Image> </View> ); })} </View> </View> </Page> </Document> ); }
问题分析
你的代码核心问题是缺少分页逻辑,所有二维码都挤在单个<Page>容器中;同时break属性的触发条件错误(index>3会导致第4个二维码就强制分页,不符合每页9个的需求),还有冗余的数组复制操作。
调整方案
以下是修改后的代码,实现了每页最多9个二维码、每行固定3个的布局:
import { Document, Page, View, Text, Image } from "@react-pdf/renderer"; interface QrCodeInfo { dealTitle: string; qrCodeId: string; qrCodeUrl: string; } function QrCodePDF(props: { qrCodeInfo: QrCodeInfo[] }) { const { qrCodeInfo } = props; // 将二维码数组按每页9个切割成子数组 const pageGroups = []; for (let i = 0; i < qrCodeInfo.length; i += 9) { pageGroups.push(qrCodeInfo.slice(i, i + 9)); } return ( <Document> {pageGroups.map((group, pageIndex) => ( <Page key={pageIndex} size="A4" style={{ backgroundColor: "#fff", padding: 10, }} > <View style={{ width: "100%", border: "1px solid #000", minHeight: "100%", display: "flex", flexDirection: "column", }} > {/* 标题栏 - 如需仅在第一页显示,可加条件:{pageIndex === 0 && ...} */} <View style={{ width: "100%", fontWeight: "bold", fontSize: "20px", textAlign: "center", padding: 10, borderBottom: "1px solid #000", }} > <Text>Qr Code for {qrCodeInfo[0]?.dealTitle}</Text> </View> {/* 二维码容器:3列布局,自动换行 */} <View style={{ flex: 1, display: "flex", flexWrap: "wrap", justifyContent: "space-around", padding: 10, gap: 8, }} > {group.map((item) => ( <View key={item.qrCodeId} style={{ width: "30%", display: "flex", flexDirection: "column", alignItems: "center", marginBottom: 12, }} > <Image src={item.qrCodeUrl} style={{ width: "100%", height: "auto" }} /> {/* 可选:显示二维码ID */} <Text style={{ fontSize: 12, marginTop: 6 }}>{item.qrCodeId}</Text> </View> ))} </View> </View> </Page> ))} </Document> ); }
关键修改点
- 分页逻辑:通过循环将原数组切割为每9个元素一组的子数组,每个子数组对应一个PDF页面
- 布局优化:用
width: 30%替代33.33%,避免padding导致容器宽度溢出,确保每行固定3个二维码 - Key稳定性:使用二维码的唯一ID
qrCodeId作为key,替代不稳定的index - 冗余代码移除:删除不必要的数组复制循环,直接使用传入的
qrCodeInfo - 容器高度控制:给外层View设置
minHeight: 100%,确保内容撑满页面
额外建议
- 若二维码尺寸不一致,可给
<Image>设置固定高度(如height: 120px)保证每行对齐 - 调整
gap和padding值可优化二维码间的间距 - 如需仅第一页显示标题,给标题View添加条件判断
{pageIndex === 0 && <View>...</View>}
内容的提问来源于stack exchange,提问作者EQ0920
相关产品推荐
相关产品推荐

