likes
comments
collection
share

前端使用 react-pdf 生成 pdf,不再依赖后端

作者站长头像
站长
· 阅读数 12

react-pdf 是一个可以在 React 应用中生成、预览、下载 PDF 文件的库。

安装

npm install @react-pdf/renderer --save

创建 pdf

创建单页 pdf

以创建一个表格视图为例,工具不支持表格组件,需要自己写表格

import React from 'react';
import { Page, Text, View, Document, StyleSheet, Image } from '@react-pdf/renderer';

// 创建样式
const styles = StyleSheet.create({
  page: {
    flexDirection: 'row',
    backgroundColor: '#E4E4E4',
    padding: 20
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1,
    backgroundColor: 'white',
    borderRadius: 5
  },
  title: {
    fontSize: 18,
    marginBottom: 10,
    textAlign: 'center'
  },
  image: {
    width: '100%',
    height: 150,
    marginBottom: 10,
    borderRadius: 5
  },
  table: {
    width: '100%',
    marginBottom: 10
  },
  tableRow: {
    flexDirection: 'row',
    borderBottom: '1 solid black',
    padding: 5
  },
  tableCell: {
    flex: 1,
    padding: 5
  }
});

// 创建pdf文档
const MyDocument = () => (
  <Document>
    <Page size="A4" style={styles.page}>
      <View style={styles.section}>
        <Text style={styles.title}>PDF Example</Text>
        <Image src="https://www.example.com/logo.png" style={styles.image} />
        <Text>Section #1</Text>
      </View>
      <View style={styles.section}>
        <Text style={styles.title}>Table Example</Text>
        <View style={styles.table}>
          <View style={styles.tableRow}>
            <View style={styles.tableCell}>
              <Text>Name</Text>
            </View>
            <View style={styles.tableCell}>
              <Text>Age</Text>
            </View>
          </View>
          <View style={styles.tableRow}>
            <View style={styles.tableCell}>
              <Text>John Doe</Text>
            </View>
            <View style={styles.tableCell}>
              <Text>30</Text>
            </View>
          </View>
          <View style={styles.tableRow}>
            <View style={styles.tableCell}>
              <Text>Jane Smith</Text>
            </View>
            <View style={styles.tableCell}>
              <Text>25</Text>
            </View>
          </View>
        </View>
      </View>
    </Page>
  </Document>
);

export default MyDocument;

多页 pdf


const MyPdfDocument = (props) => {
  return (
    <Document>
      <Page size={{ width: 708, height: 708 / 0.7 }} style={styles.page}>
        <View>
          <Image src="https://www.example.com/bg.png" />
        </View>
      </Page>

      <Page size={{ width: 708, height: 708 / 0.7 }} style={styles.page}>
        <View>
          <Image src="https://www.example.com/bg.png" />
        </View>
      </Page>
    </Document>
  );
};

内联样式

除了使用 StyleSheet.create 创建样式外,还支持使用多个样式与内联样式

  1. 使用多个样式对象:
const pageStyle = {
  flexDirection: 'row',
  backgroundColor: '#E4E4E4',
};

const sectionStyle = {
  margin: 10,
  padding: 10,
  flexGrow: 1,
};

const textStyle = {
  fontSize: 12,
  color: 'black',
};

// 使用多个样式对象
<View style={[pageStyle, sectionStyle]}>
  <Text style={textStyle}>Hello, React-PDF!</Text>
</View>
  1. 使用内联样式:
// 使用内联样式
<View style={{ flexDirection: 'row', backgroundColor: '#E4E4E4', margin: 10, padding: 10, flexGrow: 1 }}>
  <Text style={{ fontSize: 12, color: 'black' }}>Hello, React-PDF!</Text>
</View>

自定义文档尺寸

  1. A4: 默认的页面尺寸,类似标准的 A4 纸张尺寸,宽度为 210mm,高度为 297mm。
<Page size="A4">
  {/* 页面内容 */}
</Page>
  1. Letter: 类似标准的 Letter 纸张尺寸,宽度为 8.5in(英寸),高度为 11in。
<Page size="Letter">
  {/* 页面内容 */}
</Page>
  1. Legal: 类似标准的 Legal 纸张尺寸,宽度为 8.5in,高度为 14in。
<Page size="Legal">
  {/* 页面内容 */}
</Page>
  1. Custom: 自定义页面尺寸,可以设置特定的宽度和高度。
<Page size={{ width: '210mm', height: '150mm' }}>
  {/* 页面内容 */}
</Page>

你还可以指定厘米 cm

  1. Landscape: 横向页面,将宽度和高度进行调换,适合横向排列的内容。
jsxCopy code
<Page size="A4" orientation="landscape">
  {/* 页面内容 */}
</Page>

当你在 size 属性中设置一个数字值而没有指定单位时,默认的单位是“点”(points),这是印刷行业常用的度量单位,1 英寸约等于 72 点。

添加字体

如需使用中文字体需要自行下载字体文件,并注册

import chineseFontBold from '../../assets/苹方粗体字体.ttf';
import chineseFont from '../../assets/PingFang SC Regular.ttf';

// 注册字体
Font.register({ family: 'ChineseFont', src: chineseFontBold });
Font.register({ family: 'ChineseFontNormal', src: chineseFont });

// 超出宽度自动换行
Font.registerHyphenationCallback((word: string) => {
  // 1.  如果单词只有一个字符,直接返回单个字符。
  // 1.  如果单词长度大于 1,将单词拆分为单个字符的数组,并在每个字符之间插入一个空字符串,以表示单词的断开。
  if (word.length === 1) {
    return [word];
  }

  return Array.from(word)
    .map((char) => [char, ''])
    .reduce((arr, current) => {
      arr.push(...current);
      return arr;
    }, []);
});

react-pdf对中文换行处理很不友好,是根据段落中的空格去换行.

Font.registerHyphenationCallback 注册了一个自定义的断词回调函数,该函数接受一个单词字符串作为参数,并返回一个数组,其中包含了断开单词后的多个部分,断词后工具可以支持文本自动换行。

可用组件

  1. Document: 该组件代表PDF文档本身。它必须是树元素结构的根,并且在任何情况下都不应该用作另一个Reaction-pdf组件的子级。此外,它应该只有类型的子项。
  2. Page: 表示 PDF 文档中的单个页面,< Document/> 可以包含任意数量的页面,但是确保不会在除 Document 之外的任何组件中呈现页面。
  3. View: 类似于 HTML 中的 <div>,用于创建一个容器来包裹其他组件。
  4. Image: 用于在 PDF 中插入图像,可以设置图像的路径、宽度、高度等属性。
  5. Link: 用于创建一个超链接,可以链接到其他页面或 URL。
  6. Note: 用于添加注释或备注,可以在 PDF 中显示一段文本作为注释。
  7. Canvas: 用于在 PDF 中绘制图形和图像,可以自定义绘制内容。
  8. PDFViewer: 用于在应用中显示 PDF 查看器,允许用户浏览和交互 PDF 内容。
  9. Text: 用于添加文本内容,可以设置文本的样式、大小等属性。
  10. BlobProvider: 用于提供一个生成 PDF 的容器,通常与 PDFDownloadLink 配合使用。
  11. PDFDownloadLink: 用于创建一个下载链接,用户点击后可以下载生成的 PDF 文件。

更多详细信息可参考 react-pdf 组件

预览 pdf

import React from 'react';
import { PDFViewer } from '@react-pdf/renderer';
import MyPdfDocument from './MyPdfDocument';

const App = () => (
  <PDFViewer>
    <MyPdfDocument />
  </PDFViewer>
);

export default App;

注意 : PDFViewer 是 iframe 容器,react的各种provider对其内部组件都是无效的,例如 redux 的Provider,如果要与其内部组件通讯,可以通过props传值方式或纯 js 共享数据,绕过DOM。

下载 pdf

import React from 'react';
import { PDFDownloadLink } from '@react-pdf/renderer';
import MyPdfDocument from './MyPdfDocument';

const App = () => (
  <div>
    <PDFDownloadLink document={<MyPdfDocument />} fileName="my-document.pdf">
      {({ blob, url, loading, error }) => (loading ? 'Loading ...' : '下载 PDF')}
    </PDFDownloadLink>
  </div>
);

export default App;

总结

整体来说该工具还是非常好用的,推荐使用。

转载自:https://juejin.cn/post/7268080903095124003
评论
请登录