關(guān)于React項(xiàng)目中的PDF展示解決方案
本文將梳理兩種方案,涉及兩個(gè)庫(kù)react-pdf和pdf.js,使用環(huán)境為ant-design-pro腳手架創(chuàng)建的項(xiàng)目。
使用iframe標(biāo)簽
1.不需要任何依賴的兩種方式為
直接使用iframe標(biāo)簽展示pdf文件
<iframe src={fileUrl} width={'100%'} height={'100%'} style={{ minHeight: '80vh' }} />其中fileUrl為需要展示pdf的文件地址,寬高和style均可自定義,下不贅述。
如果用戶可以訪問(wèn)google,則可以使用如下地址:
<iframe
src={`http://docs.google.com/gview?url=${fileUrl}&embedded=true`}
width={'100%'}
height={'100%'}
style={{ minHeight: '80vh' }}
/>
其中fileUrl為需要展示pdf的文件地址,寬高和style均可自定義。
2.使用編譯好的靜態(tài)庫(kù)pdf.js的viewer.html展示
├── config # umi 配置,包含路由,構(gòu)建等配置 ├── mock # 本地模擬數(shù)據(jù) ├── public # 將編譯好的PDFJS放在這個(gè)目錄下 │ └── favicon.png # Favicon ├── src │ ├── assets # 本地靜態(tài)資源 │ ├── components # 業(yè)務(wù)通用組件 │ ├── e2e # 集成測(cè)試用例 │ ├── layouts # 通用布局 │ ├── models # 全局 dva model │ ├── pages # 業(yè)務(wù)頁(yè)面入口和常用模板 │ ├── services # 后臺(tái)接口服務(wù) │ ├── utils # 工具庫(kù) │ ├── locales # 國(guó)際化資源 │ ├── global.less # 全局樣式 │ └── global.ts # 全局 JS ├── tests # 測(cè)試工具 ├── README.md └── package.json
如下圖所示:

在需要展示PDF文件的地方,使用如下src即可。
<iframe
src={`pdfjs-2.2.228-dist/web/viewer.html?file=${fileUrl}`}
width={'100%'}
height={'100%'}
style={{ minHeight: '80vh' }}
/>
使用react-pdf展示
import { Pagination } from 'antd';
import React, { useState } from 'react';
import { Document, Page } from 'react-pdf/dist/esm/entry.webpack';
// @ts-ignore
const PdfViewer: React.FC<{ url: string }> = ({ url }) => {
const [numPages, setNumPages] = useState(0);
const [pageNumber, setPageNumber] = useState(1);
// @ts-ignore
const onDocumentLoadSuccess = (props: any) => {
setNumPages(props?.numPages);
};
const onChangePage = (page: any) => {
setPageNumber(page);
};
return (
<div>
<div style={{ marginBottom: 4 }}>
<a href={url} target={'_blank'} rel="noreferrer">
查看當(dāng)前文件
</a>
</div>
<Document file={url} onLoadSuccess={onDocumentLoadSuccess}>
<Page pageNumber={pageNumber} />
</Document>
<Pagination
style={{ marginTop: 4, display: 'flex', justifyContent: 'flex-end' }}
total={numPages}
simple
hideOnSinglePage
showTotal={(total) => `共 ${total} 頁(yè)`}
current={pageNumber}
pageSize={1}
size="small"
onChange={onChangePage}
/>
</div>
);
};
export default PdfViewer;
pdfjs的另一種使用方式
import { useEffect, useRef, useState } from 'react';
const PDFJsViewer = ({ pdfUrl }: any) => {
const pdfjsLib = require('pdfjs-dist/build/pdf.js');
const pdfjsWorker = require('pdfjs-dist/build/pdf.worker.entry.js');
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const canvasRef = useRef(null);
const [scale, setScale] = useState(1);
const [offset, setOffset] = useState({ x: 0, y: 0 });
const handleWheel = (e: any) => {
if (e.deltaY < 0) {
setScale((prevScale) => Math.min(prevScale + 0.1, 3));
} else {
setScale((prevScale) => Math.max(prevScale - 0.1, 0.5));
}
};
const handleMouseDown = (e: any) => {
const initialX = e.clientX - offset.x;
const initialY = e.clientY - offset.y;
const handleMouseMove = (e: any) => {
const newX = e.clientX - initialX;
const newY = e.clientY - initialY;
setOffset({ x: newX, y: newY });
};
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
};
useEffect(() => {
const canvas = canvasRef.current;
//@ts-ignore
const ctx = canvas.getContext('2d');
const loadingTask = pdfjsLib.getDocument(pdfUrl);
loadingTask.promise.then((pdf: any) => {
pdf.getPage(1).then((page: any) => {
const viewport = page.getViewport({ scale: scale });
//@ts-ignore
canvas.height = viewport.height;
//@ts-ignore
canvas.width = viewport.width;
ctx.setTransform(1, 0, 0, 1, 0, 0);
//@ts-ignore
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(scale, 0, 0, scale, offset.x, offset.y);
const renderContext = {
canvasContext: ctx,
viewport: viewport,
};
page.render(renderContext);
});
});
}, [pdfUrl, scale, offset]);
return <canvas ref={canvasRef} onWheel={handleWheel} onMouseDown={handleMouseDown}></canvas>;
};
export default PDFJsViewer;
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解webpack2+node+react+babel實(shí)現(xiàn)熱加載(hmr)
這篇文章主要介紹了詳解webpack2+node+react+babel實(shí)現(xiàn)熱加載(hmr) ,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-08-08
React觸發(fā)render的實(shí)現(xiàn)方法
這篇文章主要介紹了React觸發(fā)render的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10
React?Hooks--useEffect代替常用生命周期函數(shù)方式
這篇文章主要介紹了React?Hooks--useEffect代替常用生命周期函數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
在React中編寫(xiě)class樣式的方法總結(jié)
在TypeScript (TSX) 中編寫(xiě) CSS 樣式類有幾種方法,包括使用純 CSS、CSS Modules、Styled Components 等,本文給大家介紹了幾種常見(jiàn)方法的示例,通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-07-07
ForwardRef?useImperativeHandle方法demo
這篇文章主要為大家介紹了ForwardRef?useImperativeHandle方法demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
使用React-Router實(shí)現(xiàn)前端路由鑒權(quán)的示例代碼
這篇文章主要介紹了使用React-Router實(shí)現(xiàn)前端路由鑒權(quán)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
前端 react 實(shí)現(xiàn)圖片上傳前壓縮(縮率圖)
這篇文章主要介紹了前端 react 實(shí)現(xiàn)圖片上傳前壓縮(縮率圖),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08
React Native時(shí)間轉(zhuǎn)換格式工具類分享
這篇文章主要為大家分享了React Native時(shí)間轉(zhuǎn)換格式工具類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10

