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

如何在React-Native中打印动态PDF,导出自定义Invoice组件内容

React Native 导出组件为PDF的正确实现方案

现有代码的核心问题

  • 传参错误:Print.printToFileAsync 不支持直接传入React组件作为入参,仅接受HTML字符串、页面尺寸配置等合法参数,你当前直接传入<Invoice />的写法完全不符合API要求
  • 循环依赖:Invoice组件引入了Pdf组件,Pdf组件又反向引入Invoice组件,会触发编译报错
  • 冗余依赖:同时引入expo-print和react-native-print,二者功能重复,按需保留一个即可,Expo项目优先用expo-print

方案1:HTML模板生成PDF(推荐用于发票类文本内容,支持文字复制、排版清晰)

步骤1:抽离公共发票数据,修改Invoice.js,消除循环依赖

import React from 'react';
import { View, SafeAreaView, ScrollView, Text } from "react-native";
import { Card } from "react-native-elements";
import Pdf from "../components/Pdf";

// 抽离公共发票数据,后续生成PDF也可以复用
export const invoiceData = {
  id: "7654",
  from: "Tata 56 view Pune",
  email: "sumit@.com",
  phone: "5252146954"
}

const Invoice = () => {
  return (
    <SafeAreaView>
      <ScrollView>
        <Card>
          <Text h3>Invoice #{invoiceData.id}</Text>
          <View>
            <Text>
              <Text style={{ fontWeight: "bold" }}>From:</Text>
              {"\n"}{invoiceData.from}
              {"\n"}Email: {invoiceData.email}
              {"\n"}Phone: {invoiceData.phone}
            </Text>
          </View>
          {/* 传入发票数据给Pdf组件,不需要再引入Invoice */}
          <Pdf data={invoiceData} />
        </Card>
      </ScrollView>
    </SafeAreaView>
  );
}

export default Invoice

步骤2:修改Pdf.js,编写HTML模板生成逻辑

import * as React from 'react';
import { View, StyleSheet, Button } from 'react-native';
import * as Print from 'expo-print';
import { shareAsync } from 'expo-sharing';

export default function Pdf({ data }) {
  const printToFile = async () => {
    // 编写和React Native样式对应的HTML模板,填充公共数据
    const htmlContent = `
      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <title>Invoice #${data.id}</title>
          <style>
            body { padding: 20px; font-family: sans-serif; }
            h3 { font-size: 24px; margin-bottom: 20px; }
            .from-label { font-weight: bold; margin-bottom: 10px; }
            .info-line { margin: 5px 0; }
          </style>
        </head>
        <body>
          <h3>Invoice #${data.id}</h3>
          <div class="from-label">From:</div>
          <div class="info-line">${data.from}</div>
          <div class="info-line">Email: ${data.email}</div>
          <div class="info-line">Phone: ${data.phone}</div>
        </body>
      </html>
    `;
    // 正确传参给printToFileAsync
    const { uri } = await Print.printToFileAsync({
      html: htmlContent,
      width: 612, // A4纸宽度像素
      height: 792 // A4纸高度像素
    });
    console.log('File has been saved to:', uri);
    await shareAsync(uri, { UTI: '.pdf', mimeType: 'application/pdf' });
  }

  return (
    <View style={styles.container}>
      <Button title="Print to PDF file" onPress={printToFile} />
    </View>
  );
}

const styles = StyleSheet.create({
  container:{
    marginTop: 20
  }
}); 

方案2:视图截图转PDF(无需写HTML模板,完全复用现有React Native组件样式)

如果不想额外维护HTML样式,可以用react-native-view-shot先把Invoice组件转成图片,再插入PDF生成:

  1. 先安装依赖:expo install react-native-view-shot
  2. 给Invoice组件根节点加ref,截图后传入PDF生成逻辑即可,API调用逻辑和方案1一致,仅需把HTML模板里的内容换成<img src="data:image/png;base64,${截图base64}" style="width: 100%;" />即可。

注意事项

  • 纯React Native(非Expo)项目可直接用react-native-print替代expo-print,API逻辑基本一致
  • 可根据业务需求调整页面宽高参数,适配不同打印尺寸要求
  • 生成的PDF文件默认存在应用缓存目录,如需持久化可转存到设备公共存储目录

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 09:15:03