如何在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生成:
- 先安装依赖:
expo install react-native-view-shot - 给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
相关产品推荐
相关产品推荐

