You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>
  );
}

关键修改点

  1. 分页逻辑:通过循环将原数组切割为每9个元素一组的子数组,每个子数组对应一个PDF页面
  2. 布局优化:用width: 30%替代33.33%,避免padding导致容器宽度溢出,确保每行固定3个二维码
  3. Key稳定性:使用二维码的唯一IDqrCodeId作为key,替代不稳定的index
  4. 冗余代码移除:删除不必要的数组复制循环,直接使用传入的qrCodeInfo
  5. 容器高度控制:给外层View设置minHeight: 100%,确保内容撑满页面

额外建议

  • 若二维码尺寸不一致,可给<Image>设置固定高度(如height: 120px)保证每行对齐
  • 调整gap和padding值可优化二维码间的间距
  • 如需仅第一页显示标题,给标题View添加条件判断{pageIndex === 0 && <View>...</View>}

内容的提问来源于stack exchange,提问作者EQ0920

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 04:20:21