react-pdf预览在线PDF的使用

news/2024/9/18 17:20:18/文章来源:https://www.cnblogs.com/libo0125ok/p/18414292

1、在react项目中安装react-pdf依赖包

建议安装8.0.2版本的react-pdf,如果安装更高版本的可能出现一些浏览器的兼容性问题;

npm install react-pdf@8.0.2 -S

 

1、PC端的使用

1.1、封装一个组件:PdfViewModal.tsx

import React, { useState } from 'react'
import { Modal, Spin, Alert } from 'antd'
import { Document, Page, pdfjs } from 'react-pdf'
import 'react-pdf/dist/esm/Page/AnnotationLayer.css'
import 'react-pdf/dist/esm/Page/TextLayer.css';// 配置 PDF.js 的 worker 文件
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.js', import.meta.url).toString()interface PDFPreviewModalProps {fileName: string | nullfileUrl: string | null // 传入的 PDF 文件地址onCancel: () => void // 关闭弹框的回调
}const PDFPreviewModal: React.FC<PDFPreviewModalProps> = ({ fileName, fileUrl, onCancel }) => {const [numPages, setNumPages] = useState<number | null>(null)const [pdfWidth, setPdfWidth] = useState<number>(600) // 默认宽度为 600pxconst [loading, setLoading] = useState<boolean>(true) // 控制加载状态const [error, setError] = useState<boolean>(false) // 控制加载错误状态// 当 PDF 加载成功时,设置页面数量const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {setNumPages(numPages)setLoading(false) // 加载成功后,隐藏 loading
  }// 加载失败时,设置错误状态const onDocumentLoadError = () => {setLoading(false)setError(true) // 出错时显示错误提示
  }// 获取 PDF 页面加载后的宽度const onPageLoadSuccess = ({ width }: { width: number }) => {setPdfWidth(width)}return (<Modaltitle={`【${fileName}】预览`}openonCancel={onCancel}footer={null}width={pdfWidth + 100}style={{ top: 20 }}>{error ? (<Alert message="加载 PDF 文件失败" type="error" showIcon />
      ) : (<>{loading && (<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '80vh' }}><Spin size="large" /></div>
          )}{fileUrl && (<><div style={{ height: '88vh', overflowY: 'auto', padding: '24px' }}><Document//file={new URL('/public/temp/DXF文件要求.pdf',import.meta.url).toString()}file={fileUrl}onLoadSuccess={onDocumentLoadSuccess}onLoadError={onDocumentLoadError}>{Array.from(new Array(numPages), (el, index) => (<Page key={`page_${index + 1}`} pageNumber={index + 1} onLoadSuccess={onPageLoadSuccess} />
                ))}</Document></div></>
          )}</>
      )}</Modal>
  )
}export default PDFPreviewModal

1.2、业务代码中引入该组件

import React, { useState, useEffect, useCallback } from 'react'
import { Form } from 'antd'
import { List } from 'antd'
import PDFPreviewModal from '@/components/PdfViewModal.tsx'const PdfTest = (props: any) => {const [previewFile, setPreviewFile] = useState<any>()

const onTestPdf = () => {
  setPreviewFile({
    fileName: 'abc.pdf',
    fileUrl: 'http://****/abc.pdf'
  })
}
return (<div className="mrUp mrLink">
   <div onClick={onTestPdf}>测试预览PDF</div>
{!!previewFile?.publicFileUrl && (<PDFPreviewModalfileName={previewFile?.fileName}fileUrl={previewFile?.publicFileUrl}onCancel={() => setPreviewFile('')}/> )}</div> ) }export default PdfTest

2、H5移动端的使用

移动端加入放大、缩小、上一页、下一页的功能;

2.1、封装一个组件:PDFViwer.tsx

import React, { useState } from 'react';
import { Button, Modal, Space, Toast, Divider } from 'antd-mobile'
import { UpOutline, DownOutline, AddCircleOutline, MinusCircleOutline } from 'antd-mobile-icons'
import { Document, Page, pdfjs } from 'react-pdf';
import 'react-pdf/dist/esm/Page/AnnotationLayer.css'; // 样式导入
import 'react-pdf/dist/esm/Page/TextLayer.css'// 配置 PDF.js 的 worker 文件
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.js', import.meta.url).toString()interface PDFPreviewModalProps {fileUrl: string | null; // 传入的 PDF 文件地址
}const styleBtnDv = {display: 'flex',justifyContent: 'center',height: '1rem',alignItems: 'center',gap: '0.4rem',margin: '0.3rem 1rem',padding: '0 0.6rem',background: '#444',borderRadius: '0.5rem'
}const styleBtn = {flex: 1,display: 'flex',justifyContent: 'center',height: '0.6rem',alignItems: 'center',
}// PDF预览功能
const PDFViwer: React.FC<PDFPreviewModalProps> = ({ fileUrl }) => {const [pageNumber, setPageNumber] = useState(1);const [numPages, setNumPages] = useState(1);const [scale, setScale] = useState(0.65);// 当 PDF 加载成功时,设置页面数量const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {setNumPages(numPages);};//上一页function lastPage() {if (pageNumber == 1) {Toast.show({content: '已是第一页'})return;}const page = pageNumber - 1;setPageNumber(page);}//下一页function nextPage() {if (pageNumber == numPages) {Toast.show("已是最后一页");return;}const page = pageNumber + 1;setPageNumber(page);}//缩小function pageZoomOut() {if (scale <= 0.3) {Toast.show("已缩放至最小");return;}const newScale = scale - 0.1;setScale(newScale);}//放大function pageZoomIn() {if (scale >= 5) {Toast.show("已放大至最大");return;}const newScale = scale + 0.1;setScale(newScale);}return (<div>{/* 预览 PDF 文件 */}{fileUrl ? (<div style={{ height: 'calc(100vh - 4.5rem)', overflowY: 'auto', padding: '24px' }}><Document// 写死的pdf文件地址,用于本地测试使用,打包提交前需要注释掉// file={new URL("/public/temp/AI销售助手-宽带&套餐&战新.pdf", import.meta.url).toString()}// 真实传入的pdf地址file={fileUrl}onLoadSuccess={onDocumentLoadSuccess}><Page pageNumber={pageNumber} scale={scale} /></Document></div>
      ) : (<p>没有选择文件</p>
      )}<div style={styleBtnDv}><div style={styleBtn} onClick={lastPage}><UpOutline color='#fff' fontSize={'0.6rem'} /></div><div style={{ color: '#fff', fontSize: '0.35rem', ...styleBtn }}>{pageNumber}/{numPages}</div><div style={styleBtn} onClick={nextPage}><DownOutline color='#fff' fontSize={'0.6rem'} /></div><div style={styleBtn} onClick={pageZoomIn}><AddCircleOutline color='#fff' fontSize={'0.6rem'} /></div><div style={styleBtn} onClick={pageZoomOut}><MinusCircleOutline color='#fff' fontSize={'0.6rem'} /></div></div></div>
  );
};export default PDFViwer;

2.2、业务代码中引入该组件

import React, { useMemo, useRef, useState } from 'react'
import { ErrorBlock, Swiper, SwiperRef, Popup, } from 'antd-mobile'
import PDFViwer from '@/components/PDFViwer';const ellipsis1 = {"white-space": "nowrap","overflow": "hidden","text-overflow": "ellipsis",
}

const IntroduceDocList = (props: any) => {const { loading, introduceDocList } = props// const introduceDocList = [//   {publicFileUrl: '/public/temp/DXF文件要求.pdf', fileName:'DXF文件要求.pdf'},//   {publicFileUrl: '/public/temp/AI销售助手-宽带&套餐&战新.pdf', fileName:'AI销售助手-宽带&套餐&战新.pdf'},// ]

const [introduceDocList, setIntroduceDocList] = useState({
  {publicFileUrl: 'http://****/abc.pdf', fileName:'abc.pdf'},
{publicFileUrl: 'http://****/def.pdf', fileName:'def.pdf'},
});
const [pdf, setPdf] = useState({ id: 1 });const [showPdfViwer, setShowPdfViwer] = useState(false)const onOpenPdfViewer = (item) => {console.log(item);setPdf(item);setShowPdfViwer(true);}return (<div>{introduceDocList?.map(item => (<div data-url={item?.publicFileUrl} style={{ marginBottom: '0.3rem', fontSize: '0.4rem' }}><span style={{color:'#0B75FF'}} onClick={() => onOpenPdfViewer(item)}>{item.fileName}</span></div> ))}<Popupposition='right'visible={showPdfViwer}showCloseButtonbodyStyle={{ width: '100%' }}destroyOnClose={true}onClose={() => {setShowPdfViwer(false)setPdf({ id: 1 })}}><div style={{ padding: '0.3rem 1rem', fontSize: '0.35rem', fontWeight: 600, textAlign:'center', ...ellipsis1 }}>{pdf?.fileName}</div><div style={{ height: '100%' }} data-url={pdf?.publicFileUrl}><PDFViwer fileUrl={pdf?.publicFileUrl} /></div></Popup></div> ) } export default IntroduceDocList

效果图:

 

注意:挡在本地开发时,如果预览的pdf文件地址是线上地址,则会报跨域的问题,需要服务端解决跨域问题。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/797080.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数业智能心大陆探索生成式AIGC创新前沿

近日,数业智能心大陆参与了第九届“创客中国”生成式人工智能(AIGC)中小企业创新创业大赛。在这场汇聚了众多创新力量的研讨过程中,广东数业智能科技有限公司基于多智能体的心理健康技术探索与应用成果,从众多参赛者中脱颖而出。彰显了公司在技术创新领域的深厚实力,也为…

CSS 设置中英文和数字文本的换行

CSS 设置中英文和数字文本的换行CSS 设置中英文和数字文本的换行 在 CSS 中,可以使用不同的规则来控制中文、英文、数字等文本的换行行为。以下是一些常用的 CSS 属性和技巧,用于处理不同类型文本的换行。 1. 中文自动换行 中文字符之间通常不需要额外处理即可自动换行。不过…

ADC_DMA_双buffer传输

ADC有很多通道,但是只有一个寄存器,在使用过程中,常常使用DMA去传输,速度非常快,该文探究了在RTOS下使用两个线程以及DMA的中断,之间去同步,从而确保对ADC采集的连续性和快速性。ADC_DMA_双buffer传输线程A切换buffer地址 开启ADC转换,并使用DMA传输 等待获取DMA中断的…

ubuntu下stlink烧录stm32代码

ubuntu下stlink烧录stm32代码ubuntu下stlink烧录stm32代码,记录备忘 0、环境一、下载stlink驱动 二、编译 三、 安装stlink驱动 四、验证安装成功 usb口接stlink后,查到设备五、 烧录 六、其它

高等数学 2.2 函数的求导法则

目录1、常数和基本初等函数的导数公式2、函数的和、差、积、商的求导法则3、反函数的求导法则4、复合函数的求导法则 1、常数和基本初等函数的导数公式公式 公式(1) \((C) = 0\) (2)\((x^{\mu}) = \mu x^{\mu - 1}\)(3)\((\sin x) = \cos x\) (4)\((\cos x) = - \sin x…

自尽氚气出题人+rui 之 氚荠甲苯二酸 代码

运输计划 显然我们可以处理出每个区间正方向和反方向走的代价,那么最后的问题可以转化为每个点选择 \(0/1\) 之一,要求区间的选择两两不冲突,在这个基础上最小化代价之和。 则,可以参考 \(2-SAT\) 的思路,处理出每个点选择 \(0/1\) 两两的限制状况,不难发现这种限制应该是…

十一,Spring Boot 当中配置拦截器的“两”种方式

十一,Spring Boot 当中配置拦截器的“两”种方式 @目录十一,Spring Boot 当中配置拦截器的“两”种方式1. 准备工作:2. Spring Boot当中配置拦截器的第一种方式:通过配置类的方式3. Spring Boot 当中配置拦截器的第二种方式:4. 补充:URI 和 URL 的区别5. 总结:6. 最后:…

PbootCMS常用公司信息标签调用

以下是 PbootCMS 常用公司信息标签的表格形式,方便查阅和使用:标签名 描述 示例代码{pboot:companyname} 公司名称 {pboot:companyname}{pboot:companyaddress} 公司地址 {pboot:companyaddress}{pboot:companypostcode} 邮政编码 {pboot:companypostcode}{pboot:companycont…

Electric Power

Power How Batteries Work电池提供给外面稳定的电压氧化反应,电压会逐渐减少,知道不能给设备供电。USB PD(Power Delivery) ref:https://www.usbzh.com/article/detail-479.html USB Types Type A, Type B vs Type CType C:reversible bi-directional power capabilities bet…

记忆力训练:解锁大脑潜能的钥匙

记忆力训练:解锁大脑潜能的钥匙 在快节奏的现代生活中,良好的记忆力成为了我们学习、工作乃至日常生活中不可或缺的能力。无论是背诵长篇课文、记忆复杂数据,还是快速回顾过往经历,强大的记忆力都能让我们事半功倍。然而,随着年龄的增长和生活压力的增加,许多人发现自己的…

PbootCMS做英文站面包屑“首页”怎么处理

在使用 PbootCMS 构建英文站点时,需要将面包屑中的“首页”文字改为英文“Home”。可以通过设置面包屑标签的参数来实现这一需求。 面包屑标签 标签格式:html{pboot:position}参数说明:separator=*:分隔符,默认为 >>。 separatoricon=*:分割图标,默认为空,如使用…

PbootCMS栏目页如何调用当前栏目的文章

要在栏目页调用当前栏目的文章,可以使用 PbootCMS 提供的 {pboot:list} 标签。以下是如何在栏目页调用当前栏目的文章的具体方法。 1. 栏目页调用当前栏目的文章 假设你需要在栏目页调用当前栏目的文章,可以使用以下代码:{pboot:list num=10 scode={sort:scode} page=0}<…