react-pdf使用

2,900 阅读3分钟

安装

  • yarn
yarn add @react-pdf/renderer
  • npm
npm install @react-pdf/renderer --save

文档地址

react-pdf.org/

使用

创建PDF文档

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

// create style
const styles = StyleSheet.create({
  page: {
    backgroundColor: '#E4E4E4',
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1
  },
  first: {
    fontSize: 30,
    fontFamily: 'pinru',
  },
  second: {
    fontSize: 30,
    fontFamily: 'FangSong',
    lineHeight: 1.5,
  },
});

// create document component
const MyDocument = () => (
  <Document>
    <Page size="A4" style={styles.page}>

      <View style={styles.section}>
        <Text>Section #2</Text>
        <Text>Section #2</Text>
      </View>
    </Page>
  </Document>
)

export default MyDocument;

显示在页面上

import React from "react";
import MyDocument from './page';
import ReactPDF from "@react-pdf/renderer";
import { PDFViewer } from "@react-pdf/renderer"; 

function MyPDF () {
  
  return (
    <div>
      <PDFViewer width={1200} height={950}>
        <MyDocument />

      </PDFViewer>
    </div>
  )
}


export default MyPDF;

常用的Components

Page

  • size 设置pdf大小,支持传入height和width,也可以传入纸张类型(如:A4

image.png

  • wrap 是否允许换行

Text

  • 用于显示文本, 支持内嵌Text或Link组件 image.png

View

  • 基本视图组件 image.png

Styling

创建样式

import React from 'react'; 
import { StyleSheet } from '@react-pdf/renderer'; 

const styles = StyleSheet.create({ 
page: { backgroundColor: 'tomato' },
section: { color: 'white', textAlign: 'center', margin: 30 } }); 

使用

  • 直接在同个文件中创建
  • 也可以通过import引入进去
// index.js
import React from "react";
import { Page, Text, View, Document } from "@react-pdf/renderer";
import { styles } from './style';

const MyDocument = () => (
  <Document>
    <Page size="A4" style={styles.page}>

      <View style={styles.section}>
        <Text>Section #2</Text>
        <Text>Section #2</Text>
      </View>
    </Page>
  </Document>
)

export default MyDocument;
// style.js
import { StyleSheet } from '@react-pdf/renderer';

export const styles = StyleSheet.create({
  page: {
    fontFamily: 'song',
    lineHeight: 1.1,
    letterSpacing: -1.5
  }
  });

内联多个样式

// index.js
import React from "react";
import { Page, Text, View, Document } from "@react-pdf/renderer";

const styles = StyleSheet.create({
  page: {
    backgroundColor: '#E4E4E4',
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1
  },
  first: {
    fontSize: 30,
    fontFamily: 'pinru',
  },
});

const MyDocument = () => (
  <Document>
    <Page size="A4" style={styles.page}>

      <View style=[styles.section, styles.first, {color: '#eee'}]>
        <Text>Section #2</Text>
        <Text>Section #2</Text>
      </View>
    </Page>
  </Document>
)

export default MyDocument;

字体引入

import { StyleSheet, Font } from "@react-pdf/renderer";
import Normal from '../font/fontfamily-normal.ttf';
import FangSongNormal from '../font/FangSong-normal.ttf';

// Register font
Font.register({ family: 'pinru', src: Normal });
Font.register({ family: 'FangSong', src: FangSongNormal });

const styles = StyleSheet.create({
  first: {
    fontSize: 30,
    fontFamily: 'pinru',
  },
  second: {
    fontSize: 30,
    fontFamily: 'FangSong',
    lineHeight: 1.5,
  },
});
  • 同种字体设置不同的字体属性

image.png

踩坑记

中文乱码

image.png

  • 解决: 引入字体

image.png

import React from "react";
import { Page, Text, View, Document, StyleSheet, Font } from "@react-pdf/renderer";
import Normal from '../font/fontfamily-normal.ttf';
import FangSongNormal from '../font/FangSong-normal.ttf';

// Register font
Font.register({ family: 'pinru', src: Normal });
Font.register({ family: 'FangSong', src: FangSongNormal });

// create style
const styles = StyleSheet.create({
  page: {
    backgroundColor: '#E4E4E4',
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1
  },
  first: {
    fontSize: 30,
    fontFamily: 'pinru',
  },
  second: {
    fontSize: 30,
    fontFamily: 'FangSong',
    lineHeight: 1.5,
  },
});

// create document component
const MyDocument = () => (
  <Document>
    <Page size={{width: '1200'}} style={styles.page}>
      <View style={[styles.section, styles.first]}>
        <Text>Section #1</Text>
        <Text>春江潮水连海平,海上明月共潮生。</Text>
          <Text>滟滟随波千万里,何处春江无月明!</Text>
          <Text>江流宛转绕芳甸,月照花林皆似霰;</Text>
          <Text>空里流霜不觉飞,汀上白沙看不见。</Text>
          <Text>江天一色无纤尘,皎皎空中孤月轮。</Text>
          <Text>江畔何人初见月?江月何年初照人?</Text>
          <Text>人生代代无穷已,江月年年望相似。</Text>
          <Text>不知江月待何人,但见长江送流水。</Text>
          <Text>白云一片去悠悠,青枫浦上不胜愁。</Text>
          <Text>谁家今夜扁舟子?何处相思明月楼?</Text>
          <Text>可怜楼上月裴回,应照离人妆镜台。</Text>
          <Text>玉户帘中卷不去,捣衣砧上拂还来。</Text>
          <Text>此时相望不相闻,愿逐月华流照君。</Text>
          <Text>鸿雁长飞光不度,鱼龙潜跃水成文。</Text>
          <Text>昨夜闲潭梦落花,可怜春半不还家。</Text>
          <Text>江水流春去欲尽,江潭落月复西斜。</Text>
          <Text>斜月沉沉藏海雾,碣石潇湘无限路。</Text>
          <Text>不知乘月几人归,落月摇情满江树。
        </Text>
      </View>
      <View style={[styles.section, styles.second]}>
        <Text>#中文通过空格换行#</Text>
        <Text>仿宋是印刷字体的一种,仿照宋版书上所刻的字体,笔画粗细均匀,有长、方、扁三体,也叫仿宋体,仿宋字。</Text>
        <Text>#有空格换行#</Text>
        <Text>仿宋是印刷字体的一种,仿照宋版书上所刻的字体, 笔画粗细均匀,有长、方、扁三体,也叫仿宋体,仿宋字。</Text>
      </View>
    </Page>
  </Document>
)

export default MyDocument;

image.png

中文字体不会自动换行

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

  • 解决:在两个字直接插入空格,实现自动换行

// 填充空格
function getBlankWord(word: string) {
  return String(word).replace(/./g, (word) => word + ' ');
}

// 缩进字间距
function getWordStyle(fontSize) {
  const letterSpacing = -fontSize / 3;
  return {
    letterSpacing
  } as ReactPDF.Style;
}

<Text stlye={letterSpacing: getWordStyle(fontSize).letterSpacing}>{getBlankWord(works)} </Text>

可以基于<Text>封装一个可以换行的文本组件<BlankText>

<View>组件不能写文字,会报错

  • 解决:文本用<Text>

Error: Type mismatch

image.png