便携式文档格式(简称 pdf)非常适合共享包含大量格式精确的文本和图像的文档,尤其是当它们可能需要离线打印或阅读时。尽管大多数现代浏览器都可以显示 PDF 文件,但它们使用在独立选项卡或窗口中运行的 PDF 查看器来执行此操作,从而迫使用户离开您的网站。
PDF.js 是一个开源 javascript 库,允许您在网页内解析和呈现 PDF 文件。在本教程中,我将向您展示如何使用它从头开始创建一个完全成熟的自定义 JavaScript PDF 查看器。
如果您将 PDF 查看器添加到您的站点,您可能还会对专业的动画书插件感兴趣。javaScript 翻书以数字翻书形式展示您的内容,使用翻页效果、缩放和对多种内容类型的支持。
jquery 7 最佳 jQuery Flipbook 插件比较(免费和付费) Esther Vaati
1. 创建用户界面
让我们从创建一个新网页开始,然后向其中添加常用的html5样板代码。
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>My PDF Viewer</title> </head> <body> </body> </html>
接下来,在 中 <body>
,创建一个 <div>
可以作为 PDF 查看器容器的元素。
<div id="my_pdf_viewer"> </div>
我们的 JavaScript PDF 查看器的核心将是一个 HTML5 <canvas>
元素。我们将在其中渲染 PDF 文件的页面。<div>
因此,在元素内添加以下代码 。
<div id="canvas_container"> <canvas id="pdf_renderer"></canvas> </div>
为简单起见,我们将在任何给定时间仅在画布内呈现一页。但是,我们将允许用户通过按下按钮切换到上一页或下一页。此外,为了显示当前页码,并允许用户跳转到他们想要的任何页面,我们的界面将有一个输入字段。
<div id="navigation_controls"> <button id="go_previous">Previous</button> <input id="current_page" value="1" type="number"/> <button id="go_next">Next</button> </div>
要支持缩放操作,在界面上再添加两个按钮:一个放大,一个缩小。
<div id="zoom_controls"> <button id="zoom_in">+</button> <button id="zoom_out">-</button> </div>
在本节末尾,网页代码如下所示。
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>My PDF Viewer</title> </head> <body> <div id="my_pdf_viewer"> <div id="canvas_container"> <canvas id="pdf_renderer"></canvas> </div> <div id="navigation_controls"> <button id="go_previous">Previous</button> <input id="current_page" value="1" type="number"/> <button id="go_next">Next</button> </div> <div id="zoom_controls"> <button id="zoom_in">+</button> <button id="zoom_out">-</button> </div> </div> </body> </html>
2. 获取 PDF.js
现在我们的 JavaScript PDF 查看器的基本用户界面已经准备就绪,让我们将 PDF.js 添加到我们的网页。由于CDNJS上提供了最新版本的库 ,因此我们只需在网页末尾添加以下行即可。
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.min.js"> </script>
如果您更喜欢使用该库的本地副本,您可以从 pdfjs-dist 存储库下载它。
3. 加载 PDF 文件
在开始加载 PDF 文件之前,让我们创建一个简单的 JavaScript 对象来存储 PDF 查看器的状态。在其中,我们将包含三个项目:对 PDF 文件本身的引用、当前页面索引和当前缩放级别。
<script> var myState = { pdf: null, currentPage: 1, zoom: 1 } // more code here </script>
此时,我们可以通过调用对象的 getDocument()
方法 来加载我们的PDF文件,该方法是pdfjsLib
异步运行的。
pdfjsLib.getDocument('./my_document.pdf').then((pdf) => { // more code here });
请注意,该 getDocument()
方法在内部使用一个 XMLHttpRequest
对象来加载 PDF 文件。这意味着该文件必须存在于您自己的 Web 服务器或允许跨域请求的服务器上。
如果您手边没有 PDF 文件,您可以从Wikipedia获取我正在使用的文件。
成功加载 PDF 文件后,我们可以更新 pdf
状态对象的属性。
myState.pdf = pdf;
最后,添加对名为的函数的调用, render()
以便我们的 PDF 查看器自动呈现 PDF 文件的第一页。我们将在下一步中定义函数。
render();
4. 渲染页面
通过调用对象的 getPage()
方法 pdf
并向其传递页码,我们可以获得对 PDF 文件中任何页面的引用。现在,让 currentPage
我们将状态对象的属性传递给它。这个方法也返回一个promise,所以我们需要一个回调函数来处理它的结果。
因此,创建一个名为 render()
包含以下代码的新函数:
function render() { myState.pdf.getPage(myState.currentPage).then((page) => { // more code here }); }
要实际呈现页面,我们必须调用 回调中可用对象的render()
方法 。page
作为参数,该方法需要画布的 2D 上下文和一个 PageViewport
对象,我们可以通过调用该 getViewport()
方法获得。因为该 getViewport()
方法期望所需的缩放级别作为参数,所以我们必须将 zoom
状态对象的属性传递给它。
var canvas = document.getElementById("pdf_renderer"); var ctx = canvas.getContext('2d'); var viewport = page.getViewport(myState.zoom);
视口的尺寸取决于页面的原始大小和缩放级别。为了确保整个视口都呈现在我们的画布上,我们现在必须更改画布的大小以匹配视口的大小。就是这样:
canvas.width = viewport.width; canvas.height = viewport.height;
此时,我们可以继续渲染页面。
page.render({ canvasContext: ctx, viewport: viewport });
把它们放在一起,整个源代码看起来像这样。
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>My PDF Viewer</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.min.js"> </script> </head> <body> <div id="my_pdf_viewer"> <div id="canvas_container"> <canvas id="pdf_renderer"></canvas> </div> <div id="navigation_controls"> <button id="go_previous">Previous</button> <input id="current_page" value="1" type="number"/> <button id="go_next">Next</button> </div> <div id="zoom_controls"> <button id="zoom_in">+</button> <button id="zoom_out">-</button> </div> </div> <script> var myState = { pdf: null, currentPage: 1, zoom: 1 } pdfjsLib.getDocument('./my_document.pdf').then((pdf) => { myState.pdf = pdf; render(); }); function render() { myState.pdf.getPage(myState.currentPage).then((page) => { var canvas = document.getElementById("pdf_renderer"); var ctx = canvas.getContext('2d'); var viewport = page.getViewport(myState.zoom); canvas.width = viewport.width; canvas.height = viewport.height; page.render({ canvasContext: ctx, viewport: viewport }); }); } </script> </body> </html>
如果您尝试在浏览器中打开网页,您现在应该能够看到 PDF 文件的第一页。
您可能已经注意到,我们的 PDF 查看器的大小目前取决于正在呈现的页面大小和缩放级别。这并不理想,因为我们不希望我们的网页布局在用户与 PDF 查看器交互时受到影响。
为了解决这个问题,我们需要做的就是给 <div>
封装画布的元素一个固定的宽度和高度,并将它的 overflow
css属性设置为 auto
. 此属性在必要时为 <div>
元素添加滚动条,允许用户水平和垂直滚动。
<head>
在网页的标签内添加以下代码 :
<style> #canvas_container { width: 800px; height: 450px; overflow: auto; } </style>
当然,您可以自由更改宽度和高度,甚至可以使用媒体查询来使 <div>
元素符合您的要求。
或者,您可以包含以下 CSS 规则以使 <div>
元素看起来更加独特:
#canvas_container { background: #333; text-align: center; border: solid 3px; }
如果您现在刷新网页,您应该会在屏幕上看到如下内容:
5. 更改当前页面
我们的 JavaScript PDF 查看器目前只能显示给它的任何 PDF 文件的第一页。为了允许用户更改正在呈现的页面,我们现在必须将点击事件***器添加到我们之前创建的 go_previous
和 go_next
按钮。
在 go_previous
按钮的事件监听器中,我们必须减少 currentPage
state 对象的属性,确保它不低于 1
. 完成后,我们可以简单地 render()
再次调用该函数来呈现新页面。
此外,我们必须更新 current_page
文本字段的值,以便它显示新的页码。以下代码向您展示了如何:
document.getElementById('go_previous') .addeventListener('click', (e) => { if(myState.pdf == null|| myState.currentPage == 1) return; myState.currentPage -= 1; document.getElementById("current_page").value = myState.currentPage; render(); });
同样,在 go_next
按钮的事件***器中,我们必须增加 currentPage
属性,同时确保它不超过 PDF 文件中存在的页数,我们可以使用对象的 numPages
属性 来确定_pdfInfo
。
document.getElementById('go_next') .addEventListener('click', (e) => { if(myState.pdf == null || myState.currentPage > myState.pdf._pdfInfo.numPages) return; myState.currentPage += 1; document.getElementById("current_page").value = myState.currentPage; render(); });
最后,我们必须在文本字段中添加一个按键事件***器, current_page
以便用户只需输入页码并按 Enter 键即可直接跳转到他们想要的任何页面。在事件监听器内部,我们需要确保用户输入的数字既大于零又小于或等于 numPages
属性。
document.getElementById('current_page') .addEventListener('keypress', (e) => { if(myState.pdf == null) return; // Get key code var code = (e.keyCode ? e.keyCode : e.which); // If key code matches that of the Enter key if(code == 13) { var desiredPage = document.getElementById('current_page').valueAsNumber; if(desiredPage >= 1 && desiredPage <= myState.pdf._pdfInfo.numPages) { myState.currentPage = desiredPage; document.getElementById("current_page").value = desiredPage; render(); } } });
我们的 PDF 查看器现在可以显示 PDF 文件的任何页面。
6. 更改缩放级别
因为我们的 render()
函数在渲染页面时已经使用了 zoom
状态对象的属性,所以调整缩放级别就像增加或减少属性并调用函数一样简单。
在 zoom_in
按钮的单击事件***器中,让我们将 zoom
属性增加 0.5
.
document.getElementById('zoom_in') .addEventListener('click', (e) => { if(myState.pdf == null) return; myState.zoom += 0.5; render(); });
在按钮的单击事件*** 器中,让我们将 属性 zoom_out
递减 .zoom
0.5
document.getElementById('zoom_out') .addEventListener('click', (e) => { if(myState.pdf == null) return; myState.zoom -= 0.5; render(); });
您可以自由地为属性添加上限和下限 zoom
,但它们不是必需的。
这是所有东西放在一起时的样子。
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>My PDF Viewer</title> <script src="http://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.min.js"> </script> <style> #canvas_container { width: 800px; height: 450px; overflow: auto; } #canvas_container { background: #333; text-align: center; border: solid 3px; } </style> </head> <body> <div id="my_pdf_viewer"> <div id="canvas_container"> <canvas id="pdf_renderer"></canvas> </div> <div id="navigation_controls"> <button id="go_previous">Previous</button> <input id="current_page" value="1" type="number"/> <button id="go_next">Next</button> </div> <div id="zoom_controls"> <button id="zoom_in">+</button> <button id="zoom_out">-</button> </div> </div> <script> var myState = { pdf: null, currentPage: 1, zoom: 1 } pdfjsLib.getDocument('./my_document.pdf').then((pdf) => { myState.pdf = pdf; render(); }); function render() { myState.pdf.getPage(myState.currentPage).then((page) => { var canvas = document.getElementById("pdf_renderer"); var ctx = canvas.getContext('2d'); var viewport = page.getViewport(myState.zoom); canvas.width = viewport.width; canvas.height = viewport.height; page.render({ canvasContext: ctx, viewport: viewport }); }); } document.getElementById('go_previous').addEventListener('click', (e) => { if(myState.pdf == null || myState.currentPage == 1) return; myState.currentPage -= 1; document.getElementById("current_page").value = myState.currentPage; render(); }); document.getElementById('go_next').addEventListener('click', (e) => { if(myState.pdf == null || myState.currentPage > myState.pdf._pdfInfo.numPages) return; myState.currentPage += 1; document.getElementById("current_page").value = myState.currentPage; render(); }); document.getElementById('current_page').addEventListener('keypress', (e) => { if(myState.pdf == null) return; // Get key code var code = (e.keyCode ? e.keyCode : e.which); // If key code matches that of the Enter key if(code == 13) { var desiredPage = document.getElementById('current_page').valueAsNumber; if(desiredPage >= 1 && desiredPage <= myState.pdf._pdfInfo.numPages) { myState.currentPage = desiredPage; document.getElementById("current_page").value = desiredPage; render(); } } }); document.getElementById('zoom_in').addEventListener('click', (e) => { if(myState.pdf == null) return; myState.zoom += 0.5; render(); }); document.getElementById('zoom_out').addEventListener('click', (e) => { if(myState.pdf == null) return; myState.zoom -= 0.5; render(); }); </script> </body> </html>
我们的 PDF 查看器已准备就绪。如果您再次刷新网页,您应该能够查看 PDF 文件中存在的所有页面,并且还可以放大或缩小它们。
结论
您现在知道如何使用 PDF.js 为您的网站创建自定义 JavaScript PDF 查看器。有了它,您可以自信地提供无缝的用户体验,同时展示您组织的小册子、白皮书、表格和其他通常以硬拷贝形式分发的文档。