头图

前端(React)生成pdf终极解决方案(^_^)

最近要实现一个签合同的需求 需要前端实现合同展示、增加签名及公章、生成合同
诉求: 不允许用户随意更改复制文案

网上搜到的方法
canvas生产pdf 但会出现页面被截断情况,所以研究了一下 react-pdf@react-pdf/renderer,很好用~

@react-pdf/renderer
它会提供自带的元素,可以自定义样式,生成你想要的pdf

pdf内容

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

// 自定义字体
 Font.register({
  family: 'Oswald',
   src: 'https://64a478.ttf'
 });

const styles = StyleSheet.create({
  body: {
    paddingTop: 60,
    paddingLeft: 40,
    paddingRight: 40,
    paddingBottom: 30,
    fontFamily: 'Oswald'
  },
  title: {
    fontSize: 14,
    textAlign: 'center',
    marginBottom: 30,
  },
  subtitle: {
    fontSize: 14,
    textAlign: 'center',
    marginTop: 20,
    marginBottom: 20,
  },
  introduce: {
    fontSize: 12,
    lineHeight: 1.6,
  },
  graph: {
    fontSize: 12,
    lineHeight: 1.6,
    wrap: true,
    fontWeight: 'thin',
    color: 'rgba(0,0,0,.8)',
  },
  graphText: {
    fontWeight: 'bold',
    textDecoration: 'underline',
    color: '#000',
  },
  signImg: {
    width: '80px',
    height: '80px',
    position: 'absolute',
    left: 0,
    top: 0,
    zIndex: 2
  },
  pageNumber: {
    position: 'absolute',
    fontSize: 12,
    bottom: 30,
    left: 0,
    right: 0,
    textAlign: 'center',
    color: 'grey',
  },
});

const Content = (name?: string) => {
  return <Document>
    <Page size="A4" style={styles.body} >
      <Text style={styles.title}>BBBBB</Text>
      <Text style={styles.introduce}>This Agreement.</Text>
      <Text style={styles.subtitle}>AAAAAAa</Text>

      <Text style={styles.graph}>
        <Text style={styles.graphText}>加粗文案 </Text><Text>当前文案在一行内</Text>
      </Text>
      <Image
            style={styles.signImg}
            src="https:xxxxx.jpg"
          />
     {name ? <Text>{name}</Text> : <></>}
      <Text style={styles.pageNumber} render={({ pageNumber, totalPages }) => (
        `${pageNumber} / ${totalPages}`
      )} fixed />
    </Page>
  </Document>
}

export default Content

pdf展示

  • hooks方式生成pdf连接和blob文件

    import Content from './Content';
    const [instance] = usePDF({ document: Content('xiaoming') });
    // instance
    // loading/url/blob/error
  • DOM渲染
  • iframe方式展示,iframe底色无法更改,对于样式要求较高的不太适用

    import { PDFViewer } from '@react-pdf/renderer';
    import Content from './Content';
    
    const App = () => (
    <PDFViewer>
      <Content />
    </PDFViewer>
    );
    
    ReactDOM.render(<App />, document.getElementById('root'));
    react-pdf
    pdf链接渲染展示pdf,解决@react-pdf/renderer样式问题,可以通过第一种方式生成的blob地址或url渲染
    import React, { useState } from "react";
    import { Document, Page, pdfjs } from 'react-pdf';
    // 6版本会报错,且此方法无法解决 需要使用5版本
    // "Error: Setting up fake worker failed: "Cannot read properties of undefined (reading 'WorkerMessageHandler')".
    pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
    
    const PdfView = ({ url, loadSuccess, loadError }: any) => {
    const [numPages, setNumPages] = useState(null);
    
    function onDocumentLoadSuccess({ numPages: nextNumPages }: any) {
      setNumPages(nextNumPages);
      loadSuccess?.()
    }
      
      // 页面会渲染2层  有一层的文案可被选中  renderTextLayer设为false
    return url ? <Document file={url} onLoadSuccess={onDocumentLoadSuccess} onLoadError={loadError} options={options} >
      {Array.from(new Array(numPages), (el, index) => (
        <Page className="contract-content-pdf-page" width={800} key={`page_${index + 1}`} renderTextLayer={false} pageNumber={index + 1} />
      ))}
    </Document> : <></>
    }
    
    export default PdfView
    

这两个包结合应该可以实现不同场景不同需求的pdf文档需求~

278 声望
15 粉丝
0 条评论
推荐阅读
Bread 面包屑
定义面包屑list,每次push当前页面,push前校验是否为第一层级,第一层级清除list单页面路由需监听页面刷新,缓存list {代码...}

桃小妖阅读 297

封面图
你可能需要的多文档页面交互方案
在日常工作中,面对不同的需求场景,你可能会遇到需要进行多文档页面间交互的实现,例如在 A 页面跳转到 B 页面进行某些操作后,A 页面需要针对该操作做出一定的反馈等等,这个看似简单的功能,却也需要根据不同...

熊的猫8阅读 1.3k

封面图
把React新文档投喂给 GPT-4 后...
大家好,我卡颂。最近,React新文档终于上线了。从内容上看,新文档包括:理论知识、学习指引API介绍从形式上看,新文档除了传统的文字内容,还包括:在线Demo示意图小测验可以说是阅读体验拉满。但是,由于文档...

卡颂7阅读 7.5k评论 3

封面图
PDF 预览和下载你是怎么实现的?
在开发过程中要求对 PDF 类型的发票提供 预览 和 下载 功能,PDF 类型文件的来源又包括 H5 移动端 和 PC 端,而针对这两个不同端的处理会有些许不同,下文会有所提及。

熊的猫7阅读 3.9k评论 1

封面图
第九期:前端九条启发分享
下图是一个常见的列表, 点击列表里的详情按钮会跳到详情页, 那么也许我们在详情页修改了数据状态, 此时可能需要把修改后的状态直接传给列表页从而本地直接更新列表, 这样就不用发送新的api请求与后端交互了。

lulu_up8阅读 858

Next.js-集成状态管理器共享access token以及刷新access token解决方案
SSR和SPA最大的区别就是SSR会区分客户端Client和服务端Server,并且SSR之间只能通过cookie才能在Client和Server之间通信,例如:token信息,以往我们在SPA项目中是使用localStorage或者sessionStorage来存储,但...

Awbeci4阅读 9.1k评论 2

3个容易混淆的前端框架概念
大家好,我卡颂。有3个容易混淆的前端框架概念:响应式更新单向数据流双向数据绑定在继续阅读本文前,读者可以思考下是否明确知道三者的含义。这三者之所以容易混淆,是因为他们虽然同属前端框架范畴内的概念,但...

卡颂6阅读 930

封面图
278 声望
15 粉丝
宣传栏