前端React实现pdf在线阅读和电子合同

前端React实现pdf在线阅读和电子合同

介绍

前段时间看到网上有个趋势,今后合同也开始变成无纸化,如果要签约,只需要在网上签名,不需要本人去现场。之前没有做过,决定试试看效果。

1. 搭建页面

因为是我自建的脚手架,所以暂时先搭建个骨架用来做测试页面的开发。

提供一个简单的搭建步骤:

  1. npx create-react-app [name] --template typescript

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zEGRKtws-1644143802262)(./ReadMe.assets/image-20220206175120080.png)]

搭建好页面骨架后,我在前端周报上面翻了翻,找到了2个不错的库: js-pdfreact-pdf

  • jsPdf: 前端生成pdf文件。支持直接下载、转成data url
  • react-pdf: 实时展示pdf内容。支持打开文件和打开链接。
    • 注意: 如果使用webpack5的话,不要使用国内的npm源,一定要用国外最新版本的,否则会出现dev-server崩溃栈溢出的问题。

思路

如果要实现pdf版本的合同,我个人分为4步:

  1. 读取、展示合同内容。
  2. 制作合同。
  3. 制作合同的同时,能实时看到内容。
  4. 下载文件。

后期扩展:
5. 线上签名。
6. 盖章留戳。

1. 读取、展示合同内容

利用react-pdf的展示和读取功能,实现pdf文件的展示。首先,先不考虑文件的来源,我们以本地的测试pdf为准。

在这里插入图片描述

在开发页面引入react-pdf,下面是实现源码

import React, { useState } from 'react';
import { Document, Page } from 'react-pdf/dist/esm/entry.webpack';
// 引入样式,修复不对齐的问题
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';

import sample from './test.pdf';

const PDFDisplay = () => {
      const [totalPages, setTotalPages] = useState<number>(0)
    	const [pageNumber, setPageNumber] = useState<number>(1)
      const [file, setFile] = useState(sample)

      return (
        <>
                <Card style = {{
            margin: 8,
        }}>
            <Title level={3}>
                React-pdf 查看/显示 pdf内容
            </Title>

            <div style = {{
                margin: 8,
            }}>
                
            <div style = {{
                margin: 6,
                display: 'flex',
                flexDirection: 'row-reverse',
            }}>
            <div className="Example__container__load">
                <input onChange={onFileChange} type="file" />
            </div>
                <Button 
            style={{
                margin: 4,
            }}
            type='primary'
            onClick={turnHeadPages}
            >查看首页</Button>
            <Button 
            style={{
                margin: 4,
            }}
            type='primary'
            onClick={turnTailPages}
            >查看尾页</Button>
            <Button 
            style={{
                margin: 4,
            }}
            type='primary'
            onClick={handleReducePages}
            >上一页</Button>
            <Button 
            style={{
                margin: 4,
            }}
            type='primary'
            onClick={handleTurnPages}
            >下一页</Button>
            </div>

            <div style={{
                display: 'flex',
                justifyContent: 'center',
            }}>
            <Document file={file} 
                onLoadSuccess={(values: any) => setTotalPages(values?.numPages)} options={options} >
                <Page pageNumber={pageNumber} renderMode='svg' />
            </Document>
            </div>
            </div>

            <div style={{
                margin: 6,
                display: 'flex',
                flexDirection: 'row-reverse',
            }}>第{pageNumber}页, 共{totalPages}页</div>
        </Card>
        </>
      )
  
  }

export default PDFDisplay

可以看到文件已经被读取出来:

在这里插入图片描述

在这里插入图片描述

因为react-pdf生成了一个隐藏的dom,所以在复制文字的时候,能看到和展示的内容又区别,甚至出现了一些位置上的偏移。

在这里插入图片描述

为了解决这种不对齐的问题,需要引入样式,最大限度的避免这种样式偏移:

// 引入样式,修复不对齐的问题
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';

因为pdf是逐页读取的,我并没有采用官方doc的做法把所有的内容全部展示出来,因为需要写上4个按钮,实现灵活操作。

在这里插入图片描述

这个是按钮的方法:


    // 翻下页
    const handleTurnPages = () => {
        if (pageNumber < totalPages) setPageNumber(pageNumber + 1)
        else message.error('已经到最后一页!')
    }

    // 翻上页
    const handleReducePages = () => {
        if (pageNumber > 1) setPageNumber(pageNumber - 1)
        else message.error('已经到首页!')
    }

    // 回到首页
    const turnHeadPages = () => {
        if (pageNumber === 1) message.error('已经是首页')
        else setPageNumber(1)
    }

    // 回到尾页
    const turnTailPages = () => {
        if (pageNumber === totalPages) message.error('已经是尾页')
        else setPageNumber(totalPages)
    }

    // 上传文件
    const onFileChange = (event: any) => {
        const file = event?.target.files[0]
        const isPDF = file?.type === 'application/pdf'

        if(!isPDF) {
            message.error(`${file.name}不是一个pdf文件!`)
            return
        }
        console.log('event:', event.target.files);
        
        setFile(file)
    }

在展示过程中,如果我们的主要内容是汉字,会出现乱码情况。而汉字属于utf-8,我们需要额外引入一些东西,并且对webpack.config进行修改:

// 非拉丁语的格式问题修复
    // 此处需要修改webpack.config, CopyWebpackPlugin
    const options = {
        cMapUrl: 'cmaps/',
        cMapPacked: true,
    };

安装新的plugin:

npm i copy-webpack-plugin -S

打开webpack.config的配置文件,写入以下代码:

const CopyWebpackPlugin = require('copy-webpack-plugin');

new CopyWebpackPlugin({
  patterns: [
    {
      from: path.join(path.dirname(require.resolve('pdfjs-dist/package.json')), 'cmaps'),
      to: 'cmaps/' 
    },
  ],
}),

解决了汉字显示问题:

在这里插入图片描述

附录

1. jsPDF

  • 文档说明比较少,需要仔细阅读源码
  • 暂时不支持utf-8
    • 如果要保存为图片,需要使用html2canvas来使用, html2canvas
    • 更换为支持utf-8pdfmake或者pdfkit

实现

1. 下载pdf文件

  • 指定内容下载
    • pdf.save()
    • pdf.output()
  • canvas展示效果,并转换下载

2. 显示pdf文件

  • 本地文件展示
  • 实时下载结果展示
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端React实现录音并通过socket传输给后端的过程如下: 首先,前端需要引入相关的库和组件来实现录音功能。可以使用第三方库如Recorder.js,该库提供了录制音频的功能,并且支持转换为WAV格式。 在React组件中,可以在需要录音的地方添加一个录音按钮,并设置事件处理函数。在点击录音按钮时,调用录音相关代码,开始录制音频。 录制音频时,可以将音频数据通过Websocket进行传输。Websocket协议是一种双向通信协议,可以在浏览器和服务器之间建立持久的连接,实现实时数据传输。 在React中,可以使用第三方库如socket.io来实现Websocket的连接和数据传输。在录制音频时,将音频数据实时发送给后端服务器。 后端服务器接收到音频数据后,可以进行处理和保存。可以使用Node.js来创建一个服务器端应用,接收来自前端的音频数据,并进行相应的处理操作(如存储到数据库或进行音频处理等)。 在前端和后端之间建立的Websocket连接可以实现双向通信,因此后端也可以通过Websocket向前端发送一些消息或结果,前端可以根据接收到的消息进行相应的展示或处理。 总结来说,前端React实现录音功能,需要使用录音库和组件,通过点击按钮触发录音操作,并将音频数据通过Websocket传输给后端服务器进行处理和保存。通过Websocket建立的连接可以实现双向通信,并支持后端向前端发送消息或结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值