前端實現(xiàn) PDF 預(yù)覽的常見方案
由于在搭建個人博客時,想實現(xiàn)在線預(yù)覽 pdf 格式的個人簡歷,經(jīng)過查閱大致有三大類實現(xiàn)方案;本文共涉及以下 5 種實現(xiàn)方案,如下所示:
-
使用 HTML 標(biāo)簽
- iframe 標(biāo)簽
- embed 標(biāo)簽
- object 標(biāo)簽
-
使用第三方插件
- PDF.js
- PDFObject
-
PDF 文件轉(zhuǎn)化成圖片進行展示
-
第一類方案:使用 HTML 標(biāo)簽的實現(xiàn)預(yù)覽效果最為簡單,但兼容性最差,僅支持部分 PC 端的瀏覽器,移動端瀏覽器兼容非常差。
-
第二類方案:使用第三方庫的功能強大,還可對 pdf 文件進行操作,PC 端兼容性比較好,但在移動端會有 pdf 文件顯示不全的 bug 出現(xiàn),而且在移動端瀏覽器兼容性一般。
-
第三類方案:PDF 文件轉(zhuǎn)化成圖片進行展示的兼容性最好,能同時在 PC 端和移動端預(yù)覽,但由于是圖片格式,所以選中 pdf 文件上的文件,更加無法繼續(xù)寧操作。
因為我的個人博客尚未實現(xiàn)適配移動端,所以選擇了第二類方案。
1.使用 HTML 標(biāo)簽
該類方法實現(xiàn)簡單,但兼容性很差,慎重選擇。
1.1 iframe 標(biāo)簽
HTML 內(nèi)聯(lián)框架元素 iframe 表示嵌套的 browsing context。它能夠?qū)⒘硪粋€ HTML 頁面嵌入到當(dāng)前頁面中。
- iframe 標(biāo)簽的屬性含義請參照 MDN
-
iframe 標(biāo)簽的兼容性請參照 Can I Use
iframe 標(biāo)簽實現(xiàn)方案代碼如下所示:
<iframe src="./test.pdf" height="900px;" width="800px"></iframe>
1.2 embed 標(biāo)簽
HTML embed 元素將外部內(nèi)容嵌入文檔中的指定位置。此內(nèi)容由外部應(yīng)用程序或其他交互式內(nèi)容源(如瀏覽器插件)提供。
- embed 標(biāo)簽的屬性含義請參照 MDN
- embed 標(biāo)簽的兼容性請參照 Can I Use
embed 標(biāo)簽實現(xiàn)方案代碼如下所示:
<embed src="./test.pdf" type="application/pdf" width="100%" height="100%" />
1.3 object 標(biāo)簽
HTML object 元素(或者稱作 HTML 嵌入對象元素)表示引入一個外部資源,這個資源可能是一張圖片,一個嵌入的瀏覽上下文,亦或是一個插件所使用的資源。
- object 標(biāo)簽的屬性含義請參照 MDN
- object 標(biāo)簽的兼容性請參照 Can I Use
object 標(biāo)簽實現(xiàn)方案代碼如下所示:
<object
data="./test.pdf"
type="application/pdf"
width="100%"
height="100%"
></object>
2.使用第三方插件
能實現(xiàn)實時預(yù)覽 pdf 的插件還有許多種,但使用最多的是 PDF.js 與 PDFObject,所以本文只涉及這兩個插件。
2.1 PDF.js
2.1.1 PDF.js 簡介
PDF.js 是一款開源的 pdf 文檔讀取解析插件,可以實現(xiàn)在 html 下直接瀏覽 pdf 文檔。
- pdf.js 是基于Promise 對象而實現(xiàn)的,不了解的讀者可以先去看看MDN 上的解釋。
- pdf.js 渲染 pdf 時底層還使用了Web Worker(這會導(dǎo)致我們無法直接在本地運行官網(wǎng)下載的 demo,得在服務(wù)器上運行,詳情見注意點處),不了解的讀者可以去看一下阮一峰老師關(guān)于 Web Worker 的文章。
PDF.js 主要分為 3 層:
顯示層采用核心層,并公開更容易使用的 API 來呈現(xiàn) pdf 和從文檔中獲取其他信息。
層級 | 對應(yīng)文件 | 作用 |
---|---|---|
Core Layer(核心層) | pdf.worker.js | 核心層用于解析和解釋二進制 PDF 文檔,這一層是所有后續(xù)層的基礎(chǔ)。一般我不會直接操作核心層,而是去操作由核心層封裝的展示層,操作核心層的高級用法可去參照官網(wǎng) |
Display Layer(展示層) | pdf.js | 顯示層是對核心層進行了一個封裝,從而得到更容易使用的 API,用來展示 pdf 或從文檔中獲取其他信息。 |
Viewer Layer(查看器層) | viewer.html+viewer.css+viewer.js | 查看器構(gòu)建在顯示層上,是 PDF 查看器的 UI。 |
更多的細節(jié)請參照官網(wǎng)
2.1.2 使用 PDF.js 具體步驟
方法一
該方法是以圖片形式來展示 PDF 文檔,所以不能選中文本或復(fù)制文本。
具體步驟如下:
- 首先 npm i pdfjs-dist 下載 pdf.js 的 Prebuilt 包
- 設(shè)置 PDFJS.GlobalWorkerOptions.workerSrc 的地址
- 通過 PDFJS.getDocument(pdf 文件的 url) 處理 pdf 數(shù)據(jù),返回一個 PDFDocumentLoadingTask
- 通過 pdfDoc.getPage(i) 單獨獲取第 i 頁的數(shù)據(jù)
- 創(chuàng)建一個 canvas 元素,并設(shè)置元素的畫布屬性
- 通過 page.render 方法,將數(shù)據(jù)渲染到畫布上、
具體代碼如下:
// 第 2 步:設(shè)置 workerSrc 地址 (具體包的地址需要依自身項目決定)
import * as PDFJS from "./build/pdf.js";
import pdfjsWorker from "./build/pdf.worker.js";
PDFJS.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const pdfUrl = "./test.pdf"; //具體路徑由自身項目決定,另外這可能會涉及跨域問題可參照官網(wǎng)解決
console.log(pdfUrl);
// 第 3 步:使用 PDFJS.getDocument() 處理 pdf 文檔
PDFJS.getDocument(pdfUrl).promise.then((pdfDoc) => {
const totalPages = pdfDoc.numPages; // pdf 的總頁數(shù)
const canvasContainer = document.getElementById("#canvasContainer"); //html中需創(chuàng)建一個相應(yīng)的div容器,用于存放canvas元素
for (let i = 1; i <= totalPages; i++) {
// 第4步:使用 pdfDoc.getPage(i) 獲取第 i 頁的數(shù)據(jù)
pdfDoc.getPage(i).then((page) => {
let scaledViewport = page.getViewport({ scale: 1.5 }); //可通過scale來調(diào)節(jié)初始的縮放比
//第5步:創(chuàng)建一個 canvas 元素,并設(shè)置元素的畫布屬性
let canvas = document.createElement("canvas");
canvas.setAttribute("id", "the-canvas" + i);
canvas.height = scaledViewport.height;
canvas.width = scaledViewport.width;
let context = canvas.getContext("2d");
let renderContext = {
canvasContext: context,
viewport: scaledViewport,
};
//第 6 步: 使用 page.render 將數(shù)據(jù)渲染到畫布上
page.render(renderContext).promise.then(() => {});
canvasContainer.appendChildren(canvas); //將canvas元素加入到容器中
});
}
});
方法二
直接使用官方封裝好的 viewer.html 來展示自己的 PDF 文檔,該方法比較簡單,不用去操作 API;而且功能比較齊全,還可復(fù)制 pdf 中的文本。
具體步驟如下: 1.去官網(wǎng)下載打包好的 Prebuilt 版本壓縮包 2.將需要打開的 PDF 文檔放到與 viewer.html 文檔的同一目錄下 3.新建一個 html 文件,使用 window.open 方法 或 iframe 標(biāo)簽 來打開 viewer.html,并使用 file 字段來傳入 pdf 名字信息
該方法的更多詳細信息可參照博文
具體代碼如下:
<!-- 使用iframe -->
<!-- 該方法會受iframe標(biāo)簽兼容性限制 -->
<iframe
src="./web/viewer.html?file=test.pdf"
frameborder="0"
style="height: 800px; width: 100%"
></iframe>
<!-- 使用window.open-->
<!-- 該方法會打開新窗口 -->
<script type="text/javascript">
window.open("./web/viewer.html?file=test.pdf");//文件和 viewer.html 同路徑時
</script>
2.1.3 使用 PDF.js 的注意事項
這里的內(nèi)容非常重要,可以避免踩坑。我就是在這浪費了足足兩天的時間,最終才找到解決辦法。
注意事項一:pdf.js 需要啟動服務(wù)器才能運行,無法直接打開本地的文檔
-
原因:因為 pdf.js 渲染 pdf 文檔時使用了 Web Worker 技術(shù),該 Web Worker 無法讀取本地文件??蓞⒁娙钜环謇蠋熽P(guān)于 Web Worker 的文章
-
報錯信息:Message: Missing PDF “file:///D:/%E6%A1%8C%E9%9D%A2/pdfjs/web/test.pdf”
-
解決辦法:可通過 live-server 這個插件在本地啟動服務(wù)器然后打開相應(yīng)的 html 文件。
-
具體步驟:
- npm i live-server 安裝包
- live-server 啟動服務(wù)器 更多配置信息可參見此博客
- 打開相應(yīng)的 html 文件
注意事項二:我們的電腦上不能安裝 IDM(Internet Download Manager)這類軟件或插件。
- 報錯信息 : Unexpected server response (204) while retrieving PDF
- 原因:因為 IDM 會攔截可下載的資源,會導(dǎo)致頁面無法預(yù)覽。
- 解決辦法:直接卸載或關(guān)閉相應(yīng)的插件、軟件;也可以對軟件進行相應(yīng)的設(shè)置。更多信息可參照博文
另外使用 pdf.js 打開發(fā)票等文件時可能會出現(xiàn)字體顯示不全的 bug,可參照該博客解決 pdf.js 無法完全顯示 pdf 文件內(nèi)容的問題。
2.2 PDFObject
相對 pdf.js 來說,PDFObject 的使用非常簡單。但在手機 webview 使用兼容性不太好。
PDFObject 2.0 不向后兼容 1.0 版本,針對現(xiàn)代瀏覽器設(shè)計,支持 Chrome, Firefox, Safari (OS X and iOS), IE 9-11, and MS Edge。
更多信息可參照官網(wǎng)地址,和該篇博客PDF 預(yù)覽之 PDFObject.js 總結(jié)
使用步驟:
- 創(chuàng)建嵌入 PDF 的容器
- 告訴 PDFObject,插入的 PDF 文件路徑,以及插入到哪個容器
- 可以選擇使用 CSS 來指定視覺樣式,包括維度、邊框、邊距等
<!-- 第1步:創(chuàng)建嵌入PDF的容器 -->
<div id="pdf"></div>
<!-- 第2步:告訴PDFObject,插入的PDF文件路徑,以及插入到哪個容器 -->
<script src="library/pdfobject.js"></script>
<script>
PDFObject.embed("uploads/pdfs/dongxuemin.pdf", "#pdf");
</script>
<!-- 第3步:可以選擇使用CSS來指定視覺樣式,包括維度、邊框、邊距等 -->
<style>
.pdfobject-container {
height: 500px;
}
.pdfobject {
border: 1px solid #ccc;
}
</style>
另外還有許多第三方庫可實現(xiàn) pdf 預(yù)覽,如:vue-pdf、jquery.media.js等等。
3.PDF 文件轉(zhuǎn)化成圖片進行展示
把 PDF 轉(zhuǎn)換為圖片也有很多控件處理,例如 Aspose.Pdf、Spire.Pdf、 pdfiumviewer 等等,不同的第三方類庫使用的方法有所差異,不過思路都很類似。
由于轉(zhuǎn)成圖片將無法復(fù)制或選中 PDF 文檔的文本,所以我沒使用該方法,就沒進行進一步研究。大家可去參照其他博客。
參考博課:
- 前端預(yù)覽 PDF 文件(使用 PDFJS)
- 實現(xiàn)在線預(yù)覽 PDF 的幾種解決方案
- PDFObject.js、jquerymedia.js、pdf.js 的對比
- PDF 預(yù)覽之 PDFObject.js 總結(jié)
碼字不易,覺得有幫助的朋友點贊,關(guān)注走一波。文章來源:http://www.zghlxwxcb.cn/news/detail-807782.html
如果對本文存在疑惑,可在評論區(qū)討論,歡迎大家指正文中的錯誤觀點。文章來源地址http://www.zghlxwxcb.cn/news/detail-807782.html
到了這里,關(guān)于前端實現(xiàn) PDF 預(yù)覽的常見方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!