本文完整版:《React 实现 PDF 文件在线预览 - 手把手教你写 React PDF 预览功能》

React 实现 PDF 文件在线预览

  • 快速搭建项目
  • 渲染第一页 - React 开发预览组件
  • 渲染整个 PDF 并翻页 - React 开发预览组件
  • PDF 文本选择
  • React PDF 在线预览源代码
  • React PDFjs 搭建总结及卡拉云

在 React 项目中,很多场景都需要 PDF 文件预览功能,比如合同 ERP,销售CRM,内部文档 CMS 管理系统,都需要内置 PDF 文件在线预览功能。本文手把手教你搭建一套 PDF 预览组件嵌入到 React 项目中,实现 PDF 文件预览的所有常见功能。

跟随本教程学习完成后,你会搭出以下 PDF 在线预览效果的 React PDF 预览组件

如果你正在搭建后台管理工具,又不想处理前端问题,推荐使用卡拉云,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API ,无需懂前端,仅需拖拽即可快速搭建属于你自己的后台管理工具,一周工作量缩减至一天,详见本文文末。

本次教程中使用的技术栈

  • Vite
  • React
  • Typescript
  • pdf.js

快速搭建项目

> yarn create vite pdf-preview --template react-ts

现在我们安装下 pdf.js

通过官网的介绍,并没有发现 npm 的下载方式,这时候很多人估计就会直接安装 umd 版本的了,其实使用一个库除了看文档,看官方案例也是非常重要的,通过源代码下的 examples/webpack/main.js 文件,我们看到 pdfjs-dist 这个npm包,我们来下载

然后按照自己的习惯组织下文件目录

.
├── components
│   └── PDFRender
│       └── index.tsx
├── main.tsx
├── App.tsx
└── vite-env.d.ts

推荐阅读《5种 开源 react 移动端 ui 组件库测评推荐》

渲染第一页 - React 开发预览组件

这里我新建了一个 PDFRender 组件,先来实现一个最简单的,将 PDF 的第一页渲染出来

import * as pdf from 'pdfjs-dist'
import pdfWorker from 'pdfjs-dist/build/pdf.worker.js?url'
import React, { useLayoutEffect, useRef } from "react";pdf.GlobalWorkerOptions.workerSrc = pdfWorker;export const PDFRender: React.FC<{ src: string }> = (props) => {const canvasRef = useRef<HTMLCanvasElement | null>(null)useLayoutEffect(() => {pdf.getDocument(props.src).promise.then(pdfDocument => {return pdfDocument.getPage(1);}).then((pdfPage) => {const viewport = pdfPage.getViewport({ scale: 1.0 });const canvas = canvasRef.current;if (!canvas) {return Promise.reject()}canvas.width = viewport.widthcanvas.height = viewport.height;const ctx = canvas.getContext("2d") as CanvasRenderingContext2Dconst renderTask = pdfPage.render({canvasContext: ctx,viewport,});return renderTask.promise;}).catch(err => {console.log(err)})}, [])return (<canvas ref={canvasRef}/>)
}

细心的同学可能发现了这两行代码

import pdfWorker from 'pdfjs-dist/build/pdf.worker.js?url'
pdf.GlobalWorkerOptions.workerSrc = pdfWorker;

这是因为pdf的交互容易堵塞JS,所以 pdf.js 使用了 web worker 技术优化了性能。

最后我们使用下这个组件,看下效果

import { PDFRender } from "./components/PDFRender";const pdfFilePath = '/kalacloud-demo.pdf'export const App = () => {return (<PDFRender src={pdfFilePath} />)
}

效果如下

代码简单讲解下

  1. getDocument 去请求pdf的内容
  2. getPage 获取对应页面的内容
  3. 使用 canvas 绘制当前页面

扩展阅读:《顶级开源 react ui 组件库测评推荐》

渲染整个 PDF 并翻页 - React 开发预览组件

想渲染全部页面其实很简单,按照上面的思路,获取到页数,直接循环渲染就好了

import * as pdf from 'pdfjs-dist'
import pdfWorker from 'pdfjs-dist/build/pdf.worker.js?url'
import { useEffect, useRef, useState } from "react";pdf.GlobalWorkerOptions.workerSrc = pdfWorker;export const usePDFData = (options: { src: string, scale?: number }) => {const previewUrls = useRef<string[]>([])const urls = useRef<string[]>([])const [loading, setLoading] = useState(true)useEffect(() => {urls.current = []setLoading(true);(async () => {// 这里千万别解构,会导致 this 指向错误const pdfDocument = await pdf.getDocument(options.src).promiseconst task = new Array(pdfDocument.numPages).fill(null)await Promise.all(task.map(async (_, i) => {const page = await pdfDocument.getPage(i + 1)const viewport = page.getViewport({ scale: options.scale || 2 })const canvas = document.createElement('canvas')canvas.width = viewport.widthcanvas.height = viewport.heightconst ctx = canvas.getContext("2d") as CanvasRenderingContext2Dconst renderTask = page.render({canvasContext: ctx,viewport,});await renderTask.promise;// 分别获取不同尺寸的图片,一个用来预览一个用来展示urls.current[i] = canvas.toDataURL('image/jpeg', 1)previewUrls.current[i] = canvas.toDataURL('image/jpeg', 0.5)}))setLoading(false)})()}, [options.src])return {loading,urls: urls.current,previewUrls: previewUrls.current,}
}

接下来我们实现滚动翻页功能

  1. 点击对应页滚动到指定的位置
  2. 滚动到对应位置,高亮当前页

先看下最终的效果

首先实现点击滚动到对应的位置,非常的简单,利用 scrollIntoView api 可以快速定位到指定位置

  const goPage = (i: number) => {setCurrentPage(i)document.querySelectorAll('.page')[i]!.scrollIntoView({ behavior: 'smooth' })}

再来实现下滚动位置自动高亮页数

本质上是使用 IntersectionObserver api 来完成,监听每个页面的可见性,当可见性大于 0.5 也就是有一半的内容展示在视口里面则就确定为当前页

  const io = useRef(new IntersectionObserver((entries) => {entries.forEach(item => {item.intersectionRatio >= 0.5 && setCurrentPage(Number(item.target.getAttribute('index')))})}, {threshold: [0.5]}))

扩展阅读:《顶级开源 react admin 后台管理框架测评推荐》

PDF 文本选择

在一些特殊场景,可能会需要支持用户复制PDF上的文字,很显然 图片中的文字不能被选中。但是强大的 pdf.js 支持在相同的位置绘制文字,接下来我们实现它

import * as pdf from 'pdfjs-dist'
import pdfWorker from 'pdfjs-dist/build/pdf.worker.js?url'
+ import { TextLayerBuilder } from 'pdfjs-dist/web/pdf_viewer';
+ import 'pdfjs-dist/web/pdf_viewer.css';
import { useEffect, useRef, useState } from "react";pdf.GlobalWorkerOptions.workerSrc = pdfWorker;export const usePDFData = (options: { src: string, scale?: number }) => {const previewUrls = useRef<string[]>([])const pages = useRef<{ canvas: HTMLCanvasElement, text: HTMLDivElement }[]>([])const [loading, setLoading] = useState(true)useEffect(() => {pages.current = []setLoading(true);(async () => {const pdfDocument = await pdf.getDocument(options.src).promiseconst task = new Array(pdfDocument.numPages).fill(null)await Promise.all(task.map(async (_, i) => {const page = await pdfDocument.getPage(i + 1)const viewport = page.getViewport({ scale: options.scale || 2 })const canvas = document.createElement('canvas')canvas.width = viewport.widthcanvas.height = viewport.heightconst ctx = canvas.getContext("2d") as CanvasRenderingContext2Dconst renderTask = page.render({canvasContext: ctx,viewport,});await renderTask.promise;previewUrls.current[i] = canvas.toDataURL('image/jpeg', 0.5)+       const textContent = await page.getTextContent()+       const textLayerDiv = document.createElement('div');+       textLayerDiv.setAttribute('class', 'textLayer');+       const textLayer = new TextLayerBuilder({+         textLayerDiv,+         pageIndex: i + 1,+         viewport,+         eventBus: undefined+      });++       textLayer.setTextContent(textContent);+       textLayer.render();pages.current[i] = {canvas,text: textLayerDiv}}))setLoading(false)})()}, [options.src])return {loading,pages: pages.current,previewUrls: previewUrls.current,}
}

扩展阅读《React Echarts 使用教程 - 如何在 React 加入图表 》

React PDF 在线预览源代码

本次教程的代码可以在 github 上查看

假如你只需要预览 PDF 并且不关心浏览器兼容,那么使用 embed 只需要一行代码就能实现

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><link rel="icon" type="image/svg+xml" href="/src/favicon.svg" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Vite App</title><style>* {padding: 0;margin: 0;}body {height: 100%;width: 100%;overflow: hidden;background-color: rgb(82, 86, 89);}embed {width: 100vw;height: 100vh;}</style></head><body><embed src="/kalacloud-demo.pdf" type="application/pdf"></body>
</html>

扩展阅读:《顶级 开源 react table 表格组件测评推荐》

React PDFjs 搭建总结及卡拉云

本文介绍了如何在 React 中实现 PDF 预览功能。如果不想处理前端问题,推荐使用卡拉云,卡拉云内置各类组件,无需懂任何前端,仅需拖拽即可快速生成。

卡拉云可帮你快速搭建企业内部工具,下图为使用卡拉云搭建的内部广告投放监测系统,无需懂前端,仅需拖拽组件,10 分钟搞定。你也可以快速搭建一套属于你的后台管理工具,了解更多。

卡拉云是新一代低代码开发平台,与前端框架 Vue、React等相比,卡拉云的优势在于不用首先搭建开发环境,直接注册即可开始使用。开发者完全不用处理任何前端问题,只需简单拖拽,即可快速生成所需组件,可一键接入常见数据库及 API,根据引导简单几步打通前后端,数周的开发时间,缩短至 1 小时。立即免费试用卡拉云。

扩展阅读:

  • React Router 6 (React路由) 最详细教程
  • 全栈实战:React + Nodejs 搭建带预览的「上传图片/预览」管理后台
  • React Draggable 实现拖拽 - 最详细中文教程
  • 最好用的 8 款 React Datepicker 时间日期选择器测评推荐
  • React form 表单验证终极教程

React 实现 PDF 文件在线预览 - 手把手教你写 React PDF 预览功能相关推荐

  1. java flexpaper_java web word文件 pdf文件在线预览源码(flexpaper)

    [实例简介]java web word文件 pdf文件在线预览源码 经过测试 [实例截图] [核心代码] BrowsenOnline html, body{ height:100%; } body { ...

  2. vue-pdf实现pdf文件在线预览

    1. 前言 PDF文件在线预览的功能相信大家都是有遇到过的, 但在我平时的项目中, 公司提供了相应的插件, 但是在h5等其他项目中, 我们还是只能靠自己呀! 今天就大概说一下 vue-pdf 这个组件 ...

  3. html5 pdf.js 使用方法,PDF 文件在线预览(pdf.js 使用教程)

    因项目开发需要在线展示 PDF文件,为解决 PDF文件 在浏览器打开后电子签章.电子签名等展示不全且部分浏览器兼容问题特利用pdf.js解决该问题: pdf.js框架为HTML5,无需任何本地支持,兼 ...

  4. pdfjs-dist 实现pdf文件在线预览

    pdfjs-dist 实现pdf文件在线预览 实现效果 实现过程 (1)安装pdfjs-dist (2)代码部分 (3)原理 项目要求实现pdf文件在线预览,并且pdf预览通过上下页滚动pdf,且兼容 ...

  5. vue 实现pdf文件在线预览

    PDF文件在线预览的功能相信大家都是有遇到过的,这边有两种实现方法,大家可以借鉴参考下 第一种,使用vue-pdf 安装 npm install --save vue-pdf 页面代码 <tem ...

  6. #网页中动态嵌入PDF文件/在线预览PDF内容#

    摘要:在web开发时我们有时会需要在线预览PDF内容,在线嵌入pdf文件: 问题1:如何网页中嵌入PDF: 在网页中: 常用的几种PDF预览代码片段如下: 代码片段1: 1 <object ty ...

  7. 网页中动态嵌入PDF文件/在线预览PDF内容

    网页中动态嵌入PDF文件/在线预览PDF内容https://www.cnblogs.com/xgyy/p/6119459.html #网页中动态嵌入PDF文件/在线预览PDF内容# 摘要:在web开发 ...

  8. ftp服务器在线查看文件内容,ftp服务器PDF文件在线查看的实现方法

    URL形式: // http://localhost:2692/PDFVIEWER/web/viewer.html?file=http://localhost:2692/TOV/DASystem/Ge ...

  9. ftp服务器PDF文件在线查看

    曾做过电厂的项目,有一些功能需要和甲方的厂家对接,其中就有需要实现甲方ftp服务器上的PDF.JPG等文件的查看功能.就PDF文件为例,这里使用的是pdf插件,需要将参数通过链接发给ftp,获取到PD ...

  10. ftp服务器在线浏览,ftp服务器PDF文件在线查看的实现方法

    URL形式: // http://localhost:2692/PDFVIEWER/web/viewer.html?file=http://localhost:2692/TOV/DASystem/Ge ...

最新文章

  1. 利用box-shadow绘图
  2. SpringBoot+MyBatis+ElementUI中对于时间格式化问题的处理
  3. gns3 1.3.9升级到gns3 1.3.11后,升级gns3 iouvm解决版本不匹配问题
  4. mysql集合与集合的子集_大集合List分为多个子集合
  5. 安装MAMP后的控制台访问mysql问题
  6. visual studio code(vscode)的使用(快捷键)
  7. Hadoop上传文件到HDFS失败
  8. android studio增量包,Android Studio 更新升级之增量升级
  9. 三维扫描仪修复的功能有多重要
  10. 【计及DG和相关性的纯交流三点估计随机潮流计算方法】
  11. Transition 总结
  12. Field userDao ....service.impl...'com.lzj.springcloud.dao.UserDao' that could not be found
  13. 4 security management strategies for data center consolidation
  14. python的图导入origin,导入Numpy或OriginPro和Python时出现问题
  15. 基于stm32+LM2904+esp8266的噪声预警系统
  16. Java命令 - 关于jvm性能优化与gc优化相关参数设置
  17. 南方农机杂志南方农机杂志社南方农机编辑部2022年第24期目录
  18. 高级操作系统选择判断总结
  19. windows命令行指令
  20. 二叉树练习题及答案解析

热门文章

  1. arcgis地理配准_【更新70篇】地理数据科学技术文章合集,欢迎大家点赞、在看、转发三连!...
  2. abaqus python教程_Abaqus-python脚本到底应该怎么写?一文带你入门
  3. 计算机主机接口,计算机主机背面有哪些接口
  4. FPGA:生成占空比可调的PWM波
  5. UE4 Ultra Dynamic Sky 参数翻译及功能概述
  6. 微信小程序地图和百度地图定位位置不一样
  7. 小米便签源码分析——UI包
  8. UltraEdit使用正则表达式(通配符)进行查找和替换
  9. linux 安装Elasticsearch
  10. 2021年JRebel最新激活方式