当前位置: 首页 > news >正文

React--》实现 PDF 文件的预览操作

PDF作为最常见的电子文档格式如何实现电子签名和盖章功能,成为了每个开发者和企业必须面对的问题。在这篇文章中将深入探讨如何在React应用中集成PDF预览功能

要实现对pdf进行预览操作首先我们要实现对pdf的预览操作,实现预览操作的方式有很多如使用pdfjs-dist、react-pdf、pdf-viewer等预览工具,它们之间的区别如下所示:

1)pdfjs-dist:基于Mozilla的pdf.js项目的js库,提供了丰富的API且允许开发者对pdf文件进行各种操作,如缩放、旋转、搜索等,功能强大兼容性好,支持PC端和移动端浏览器。

2)react-pdf:专门为react框架设计的pdf渲染库,它基pdfjs-dist但提供了更加简洁易用的react组件接口,通过react-pdf可以轻松地在React应用中实现PDF预览功能。

3)pdf-viewer:基于vue的pdf渲染组件,与react-pdf类似也提供了简洁易用的API,方便开发者在vue应用中实现pdf预览功能,优点是易于集成和使用同时支持vue的响应式布局和组件化开发。

pdfjs-dist、react-pdf和pdf-viewer都是实现前端PDF预览功能的优秀工具,它们各有优缺点,选择哪个取决于你的具体需求和技术栈,因为此次采用的react框架,所以这里我们就使用react-pdf进行预览操作,预览的样式布局我们就参考e签宝:地址 的样式布局来进行实现吧,如下所示:

终端执行如下命令按照pdf预览插件,关于这个插件详细具体的使用,可以参考:npm 或 官网 进行查看,这里不再赘述:

npm i react-pdf

pdf预览:安装完成之后,我们在网上随便下载一个pdf资料来进行演示,这里我们要使用react-pdf进行预览就要引入配置pdf的worker文件,然后通过Document设置文档容器,Page设置pdf每一页的内容,如下代码所示:

import { useState, useRef } from 'react';
import { pdfjs, Document, Page } from 'react-pdf';
import 'react-pdf/dist/esm/Page/AnnotationLayer.css'
import 'react-pdf/dist/esm/Page/TextLayer.css';
import "./index.less"
// 配置 PDF.js 的 worker 文件
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString();const PDFPreview = () => {const [numPages, setNumPages] = useState<number>(0);const [pdfWidth, setPdfWidth] = useState<number>(600); // 默认宽度为 600pxconst pdfWidthRef = useRef(pdfWidth); // 用于存储和防止频繁更新 pdfWidth 的 refconst pageRefs = useRef<Array<HTMLDivElement | null>>([]);return (<div className='pdf-container'><div className='pdf-center'><div className='pdf-center-bottom' style={{ overflowY: 'auto' }}><Documentfile={new URL('/public/test.pdf', import.meta.url).toString()}onLoadSuccess={({ numPages }) => setNumPages(numPages)}onLoadError={(error) => console.log('Error loading PDF:', error)}>{numPages && Array.from(new Array(numPages), (el, index) => (<div key={`page-container_${index + 1}`} className='pdf-content-item'ref={(ref: any) => pageRefs.current[index] = ref}><Pagewidth={pdfWidthRef.current} // 使用 ref 存储的宽度key={`page_${index + 1}`}pageNumber={index + 1}onLoadSuccess={({ width }) => setPdfWidth(width)}/></div>))}</Document></div></div></div>);
};export default PDFPreview;

效果如下所示:

布局调整:接下来我们仿照e签宝的样式来对pdf预览进行调整布局,这里我们用到了antd和其对应的icon内容,可以提前安装一下对应的依赖,最终实现的效果如下所示:

<div className='pdf-container'><div className='pdf-left'><div className='pdf-left-top'>操作内容</div></div><div className='pdf-center'><div className='pdf-center-top'><div className='slider'><Slider value={percentage} min={50} max={300} step={10} tooltip={{ formatter: null }} style={{ width: '150px' }}onChange={handlePercentageChange} /><div className='slider-value'>{percentage}%</div></div><div className='pagination'><Pagination simple total={numPages} pageSize={1} onChange={handlePageChange} /></div><IsFullScreen /></div><div className='pdf-center-bottom' ref={scrollContainerRef} style={{ overflowY: 'auto' }}><Documentloading={<IsLoading />}file={new URL('/public/test.pdf', import.meta.url).toString()}onLoadSuccess={({ numPages }) => setNumPages(numPages)}onLoadError={(error) => console.log('Error loading PDF:', error)}>{numPages && Array.from(new Array(numPages), (el, index) => (<div key={`page-container_${index + 1}`} className='pdf-content-item'ref={(ref: any) => pageRefs.current[index] = ref}><Pagewidth={pdfWidthRef.current} // 使用 ref 存储的宽度key={`page_${index + 1}`}pageNumber={index + 1}onLoadSuccess={({ width }) => setPdfWidth(width)}/></div>))}</Document></div><div className='operate'><Button icon={<VerticalAlignTopOutlined />} onClick={scrollToTop}></Button><Button icon={<VerticalAlignBottomOutlined />} onClick={scrollToBottom}></Button></div></div><div className='pdf-right'><div className='pdf-right-top'>位置信息</div></div>
</div>

基础操作:接下来开始实现预览pdf顶部的一些按钮操作,实现放大缩小、切换分页、回到顶部底部操作,核心逻辑就是改变pdf预览的宽度以及切换滚动距离,很容易就实现了,代码如下所示:

// 防抖处理滑块值变化
const handlePercentageChange = useCallback(debounce((value: number) => {setPercentage(value);const newWidth = 600 * (value / 100);setPdfWidth(newWidth);pdfWidthRef.current = newWidth;}, 100), []
);
const handlePageChange = (pageNumber: number) => {const targetPageRef = pageRefs.current[pageNumber - 1];if (targetPageRef && scrollContainerRef.current) {const offsetTop = targetPageRef.offsetTop;scrollContainerRef.current.scrollTop = offsetTop -80;}
};
// 平滑滚动到顶部
const scrollToTop = () => {if (scrollContainerRef.current) {smoothScrollTo(0);}
};
// 平滑滚动到底部
const scrollToBottom = () => {if (scrollContainerRef.current) {const maxScrollHeight = scrollContainerRef.current.scrollHeight;smoothScrollTo(maxScrollHeight);}
};
// 平滑滚动到指定位置
const smoothScrollTo = (targetPosition: number) => {if (scrollContainerRef.current) {const currentPosition = scrollContainerRef.current.scrollTop;const distance = targetPosition - currentPosition;const duration = 500; // 滚动持续时间(毫秒)let startTime: number;const scrollStep = (timestamp: number) => {if (!startTime) startTime = timestamp;const progress = timestamp - startTime;const increment = distance * (progress / duration);scrollContainerRef.current.scrollTop = currentPosition + increment;if (progress < duration) {requestAnimationFrame(scrollStep);} else {scrollContainerRef.current.scrollTop = targetPosition;}};requestAnimationFrame(scrollStep);}
};

全屏操作:对于全屏操作这里我封装了个组件,然后直接引入该组件进行使用就行了,如下所示:

import { useState } from "react";
import { ArrowsAltOutlined, ShrinkOutlined } from "@ant-design/icons";const IsFullScreen = () => {const [isFullScreen, setIsFullScreen] = useState(false);// 进入全屏模式的函数const enterFullScreen = () => {const elem: any = document.documentElement; // 获取整个文档元素if (elem.requestFullscreen) {elem.requestFullscreen(); // 标准全屏} else if (elem.mozRequestFullScreen) {elem.mozRequestFullScreen(); // Firefox} else if (elem.webkitRequestFullscreen) {elem.webkitRequestFullscreen(); // Chrome, Safari 和 Opera} else if (elem.msRequestFullscreen) {elem.msRequestFullscreen(); // Internet Explorer / Edge}setIsFullScreen(true); // 更新状态,进入全屏};// 退出全屏模式的函数const exitFullScreen = () => {const elem: any = document; // 获取整个文档元素if (elem.exitFullscreen) {elem.exitFullscreen(); // 退出全屏} else if (elem.mozCancelFullScreen) {elem.mozCancelFullScreen(); // Firefox} else if (elem.webkitExitFullscreen) {elem.webkitExitFullscreen(); // Chrome, Safari 和 Opera} else if (elem.msExitFullscreen) {elem.msExitFullscreen(); // Internet Explorer / Edge}setIsFullScreen(false); // 更新状态,退出全屏};return (<div style={{ cursor: 'pointer' }} onClick={isFullScreen ? exitFullScreen : enterFullScreen}>{isFullScreen ? <ShrinkOutlined /> : <ArrowsAltOutlined />}</div>);
};export default IsFullScreen;

至此对于pdf的预览以及一些基础操作完成了,感兴趣的朋友可以继续开发其他功能!

http://www.lryc.cn/news/603484.html

相关文章:

  • 配置daemon.json使得 Docker 容器能够使用服务器GPU【验证成功】
  • VitePress学习笔记
  • 彻底清理ArcGIS 10.2残留的步骤
  • Windows使用Powershell自动安装SqlServer2025服务器与SSMS管理工具
  • Vue.js 完全指南:从入门到精通
  • getgff.py脚本-python006
  • openbmc 阈值sensor分析
  • 计算机视觉(CV方向)算法基础
  • SketchUp纹理贴图插件Architextures安装使用图文教程
  • Linux sshfs 安全挂载远程文件系统 命令详解
  • Angular面试题目和答案大全
  • AR辅助前端设计:虚实融合场景下的设备维修指引界面开发实践
  • Mac m系列芯片安装node14版本使用nvm + Rosetta 2
  • YotoR模型:Transformer与YOLO新结合,打造“又快又准”的目标检测模型
  • VUE -- 基础知识讲解(一)
  • 【MySQL】数据库的简单介绍
  • Node.js 内置模块
  • 安卓模拟器 adb Frida hook 抓包
  • uniapp如何封装uni.request 全局使用
  • 自适应双门限的能量检测算法
  • 2025年中科院1区SCI-冬虫夏草优化算法Caterpillar Fungus Optimizer-附Matlab免费代码
  • 09 RK3568 Debian11 ES8388 模拟音频输出
  • 电磁兼容(EMC):整改案例(十三)屏蔽外壳开孔解决433MHz无线通信问题
  • vue3+vite 使用liveplayer加载视频
  • 【学习路线】游戏开发大师之路:从编程基础到独立游戏制作
  • BehaviorTree.Ros2 编译教程
  • java导入pdf(携带动态表格,图片,纯java不需要模板)
  • 前端基础之《Vue(26)—Vue3两种语法范式》
  • Spring MVC数据传递全攻略
  • 黑客哲学之学习笔记系列(一)