H5实现PDF文件预览,使用pdf.js-dist进行加载

H5实现PDF文件预览,使用pdf.js-dist进行加载

一、应用场景

在H5平台上预览PDF文件是在原本已经开发完成的系统中新提出的需求,原来的系统业务部门是在PC端进行PDF的预览与展示,但是现在设备进行了切换,改成了安卓一体机进行文件预览。因此出现了PDF文件无法显示的问题,此前使用的是vue-pdf插件和PDFObject插件实现的预览,所以这两个插件是无法实现PDF预览了,改为了pdfjs-dist进行PDF的预览。

二、实现方法

法一:通过js代码实现预览

该方法适用于预览后端返回的文件流内容,但是此方法是将pdf展示在画布上,因此无法选中或复制文本内容。

1、定义一个容器用来展示PDF

这个容器可以是div,也可以是canvas,由于pdfjs渲染pdf文件是一页一页进行展示的,因此需要循环进行展示。

vue 复制代码
<template>
    <div>
        <canvas v-for="pageIndex in pdfPages" :id="`pdf-canvas-` + pageIndex" :key="pageIndex" style="display: block;width:100%"></canvas>
    </div>
</template>
2、加载pdf

由于我这边的文件来自于后端返回的文件流,因此我需要将base64进行转换后进行展示。

js 复制代码
<script lang="ts" setup>
import { getDocument } from 'pdfjs-dist'
import * as pdfjsLib from 'pdfjs-dist'
import * as pdfjsWorker from 'pdfjs-dist/build/pdf.worker.mjs'
let pdfDoc = reactive({}); // 保存加载的pdf文件流
let pdfPages = ref(0); // pdf文件的页数
let pdfScale = ref(1.0); // 缩放比例

const pdfLoader = async () => {
    //...此处为接口请求,返回的res.data.result.fileByte为pdf的文件流内容
	pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js';
	const blob = new Blob([res.data.result.fileByte], { type: 'application/pdf' });
	let arrayBuffer = base64ToBuffer(res.data.result.fileByte);
	const loadingTask = pdfjsLib.getDocument(arrayBuffer);
	loadingTask.promise.then((pdf) => {
		pdfDoc = pdf; //获取pdf文档流
		pdfPages.value = pdf.numPages; //获取pdf文件的页数
		renderPage(1);//从第几页开始渲染
	});
}
//渲染pdf文件
const renderPage = (num) => {
	pdfDoc.getPage(num).then((page) => {
		const canvasId = 'pdf-canvas-' + num;
		const canvas = document.getElementById(canvasId);
		const ctx = canvas.getContext('2d');
		const dpr = window.devicePixelRatio || 1;
		const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
		const ratio = dpr / bsr;
		const viewport = page.getViewport({ scale: pdfScale.value });
		canvas.width = viewport.width * ratio;
		canvas.height = viewport.height * ratio;
		canvas.style.width = viewport.width + 'px';
		canvas.style.height = viewport.height + 'px';
		ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
		const renderContext = {
			canvasContext: ctx,
			viewport: viewport,
		};
		page.render(renderContext);
		if (num < pdfPages.value) {
			renderPage(num + 1);
		}
	});
};
</script>

法二:通过内置的viewer.html文件进行预览

该方法适用于pdf在本地,或者是通过后端返回url链接的,操作比较简单, 不需要操作API,而且可以复制pdf中的文本内容,如果需要修改部分功能的话,可以直接修改html中的代码进行实现。

1、下载pdf.js官方插件

打开官网的链接(链接地址),找到下方的Stable按钮,下载稳定版本的插件包。

2、将下载后的文件放到项目中

将下载后的压缩包解压后,会看到这两个文件夹,将这两个文件夹添加到项目中。

其中在web文件夹中有一个viewer.html文件,下面将借助这个封装好的文件实现pdf的预览。实现原理是将文件的路径传给viewer.html,从而解析该文件进行预览。

如果你的文件在本地,那么可以把这个文件放到与viewer.html同一个路径下,然后实现预览。

js 复制代码
window.open("./js/pdfJS/web/viewer.html?file=/pdf/files/compressed.tracemonkey-pldi-09.pdf");//注意路径是否正确

如果你的文件是通过后端拿到的URL,那么需要修改后面的pdf文件的路径,注意需要提前将路径转码。

js 复制代码
let fileUrl = encodeURIComponent('http:.....xxx.pdf') //将路径转码
window.open("http:...viewer.html?file=" + fileUrl);

三、注意事项

pdf.js无法直接在本地预览文件,需要启动服务器才能运行,例如tomcat、live-server 插件等。查阅相关资料后,发现是因为 pdf.js 渲染 pdf 文档时使用了 Web Worker 技术,该 Web Worker 无法读取本地文件。

相关推荐
gnip4 小时前
企业级配置式表单组件封装
前端·javascript·vue.js
一只叫煤球的猫5 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
excel6 小时前
Three.js 材质(Material)详解 —— 区别、原理、场景与示例
前端
掘金安东尼6 小时前
抛弃自定义模态框:原生Dialog的实力
前端·javascript·github
hj5914_前端新手10 小时前
javascript基础- 函数中 this 指向、call、apply、bind
前端·javascript
薛定谔的算法10 小时前
低代码编辑器项目设计与实现:以JSON为核心的数据驱动架构
前端·react.js·前端框架
Hilaku10 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
yangcode10 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu10 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu10 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript