目录Pdf.js有两种使用方式把pdf.js当作静态资源使用npm下载,通过import使用API(记录一下,防止忘记)Pdf.js有两种使用方式在这次的项目中用到了pdf文件的预览功能,选择了pdf...
目录
Pdf.js有两种使用方式把pdf.js当作静态资源使用
npm下载,通过import使用
API(记录一下,防止忘记)
Pdf.js有两种使用方式
在这次的项目中用到了pdf文件的预览功能,选择了pdf.js去预览pdf文件,实现滑动展示所有的pdf
通过 npm 下载直接下载 pdf.js 库,当作静态资源使用
把pdf.js当作静态资源使用
最开始我采取的是把pdf.js当作静态资源使用,使用方法如下:
官网下载后解压项目得到 pdf.js放到项目文件夹 /public/static/ 下
直接将 web/viewer.html 后面的 file 跟上自己自己的 pdf 文件即可
contentUrl.current = content.includes("pdf")
? `/static/pdfjs-3.1.81-dist/web/viewer.html?file=${content}`
: content;
<iframe src={contentUrl.current}></iframe>
使用静态资源时,如果需要更改他的默认样式需要自己手动改源代码
同时可能我们遇到了跨域问题,我们需要在源码中的判断跨域代码注释掉

使用静态资源的问题是在移动端不能手势放大缩小,需要我们自己编写代码然后修改源代码强制放大缩小
这种方式不细讲,网上很多使用方式都是通过使用静态资源,可以自行去查看,这里只讲一个大概。
npm下载,通过import使用
方法如下:
npm install pdfjs-dist
const contentRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
//content就是 iframe 请求的url,这里是因为我的项目里面需要判断下他url是否涵盖了pdf
//如果涵盖了才使用pdf.js
content.includes('pdf')
//重点是 loadPdf() 这个函数,就是我们使用 pdf.js 的函数
? loadPdf(contentRef.current, content, loadingRef.current)
: null;
}, [content]);
<div className="content-wrapper" ref={contentRef}>
{content.includes('pdf') ? null : <iframe src={content}></iframe>}
<div className="loading" ref={loadingRef} style={{ display: 'none' }}></div>
</div>
importjavascript * as pdf from 'pdfjs-dist';
import pdfWorker from 'pdfjs-dist/build/pdf.worker.js?url';
pdf.GlobalWorkerOptions.workerSrc = pdfWorker;
/**
* @desc 使用pdf.js加载pdf
* @param contentDom
* @param url
*/
export const loadPdf = async (
contentDom: HTMLDivElement | null,
url: string,
loadingDom: HTMLDivElement | null
) => {
//得到请求的 pdf 文件
const loadingTask = pdf.getDocument({
url: url,
disableRange: true
});
//loading效果,下载pdf过程中展示loading
loadingTask.onProgress = () => {
if (loadingDom) {
loadingDom.style.display = 'block';
}
};
loadingTask.promise.then((pdfDoc) => php{
//下载完成时,loading消失
if (loadingDom) {
loadingDom.style.display = 'none';
}
//得到 pdf 总页数
const totalPages = pdfDoc.numPages;
for (let i = 1; i <= totalPages; i++) {
pdfDoc.getPage(i).then((page) => {
const canvas = document.createElement('canvas');
canvas.setAttribute('id', `the-canvas${i}`);
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
const dpr = window.devicePixelRatio || 1;
const scaledViewport = page.getViewport({ scale: 1 });
canvas.height = Math.floor(scaledViewport.height * dpr);
canvas.width = Math.floor(scaledViewport.width * dpr);
canvas.style.width = document.body.clientWidth + 'px';
canvas.style.height =
document.body.clientWidth / (canvas.width / canvas.height) + 'px';
const transform = dpr !== 1 ? [dpr, 0, 0, dpr, 0, 0] : undefined;
const renderContext = {
canvasContext: ctx,
viewport: scaledViewport,
transform: transform
};
page.render(renderContext);
contentDom?.appendChild(canvas);
});
}
});
};
上面的代码展示了我使用pdf.js的整个使用过程,主要思路是先获取到pdf文件,然后得到总页数后通过生成响应页数的canvas,然后再渲染到页面上展示pdf
这里需要注意的是scaledViewport.height得到的是你的pdf文件本身的宽高,我们需要通过这个宽高进行适配我们自己的屏幕,同时需要保证他的清晰度,所以我们需要保证canvas两个宽高的尺寸是一致的。
canvas 本身有两个宽高,标签的 width 和 height 是绘画区域实际宽度和高度,绘制的图形都是在这个上面。而 style 的 width 和 height 是 canvas 在浏览器中被渲染的高度和宽度,如果 canvas 标签中没有定义 width 和 height 时,默认会给宽 300 高 150,所以就出现了拉伸的效果,不想用默认的宽高的话,尽量在标签中写上宽高的属性。
所以,如上面的代码一样,宽度就是整个屏幕的宽度,但是每个pdf页面的高度,需要保证和canvas.width/canvas.height的尺寸一致
canvas.style.height = document.body.clientWidth / (canvas.width / canvas.height) + 'px';
这样就能展示pdf文件了
这里又存在一个问题,文件过大,而pdf.js的渲染原理是需要将整个pdf文件下载下来后,再进行展示,这就导致了白屏的时间过长,用户体验感不好,然后我们就想到了分片下载
我们需要在 getDocument()这个api上增加一些配置
const loadingTask = pdf.getDocument({
url: url,
//disableRange: true,
rangeChunkSize: 65536 * 16,
disableAutoFetch: true
});
分片下载还有一个很重要的点,就是需要判断下你访问的pdf是否支持分片下载,使用了分片下载的请求是后续会通过你的分片大小发送206请求
HTTP206状态码代表的意思是 请求已成功处理,但仅返回了部分内容,即 HTTP 206 Partial Content 响应状态。
HTTP 206 (Http Status Code 206) 状态是HTTP协议的一种响应码,是我们请求访问网站时,服务器端返回的2xx 成功状态系列响应码之一。

查看是否支持分片下载

需要有这个响应头才是支持分片下载 accept-range:bytes
但后面我们遇到一个问题:我们的pdf链接存在这个响应头,但却不支持分片下载,后面通过对比发现是这个响应头 Access-control-expose-headers 的问题
响应标头 Access-Control-Expose-Headers 允许服务器指示哪些响应标头应该对浏览器中运行的脚本可用,以响应跨源请求。
我们最开始这个响应头里面的内容没有Access-Control-Expose-Headers,意味着就算存在 accept-range 这个响应头,浏览器也不可用,所以在后面我们添加上这个响应头的内容后就可以使用分片下载了。
API(记录一下,防止忘记)
这个api来源于掘金的某位大佬
最后,发现可能是这个库的问题还是什么,目前不太清楚,他总是从13M以上才开始快速渲染,而我们当时的文件大小差不多也是13M,所以采用了分片下载后,还是存在一段比较长的白屏时间,所以最后还是选用了将pdf转成图片再显示的形式。
以上就是文件预览PDF.js使用技巧示例总结的详细内容,更多关于文件预览PDF.js的资料请关注我们其它相关文章!










