我肥來啦😁。看到 Redux教程突破3w的瀏覽量,小竊喜,很高興本身的文章可以幫助到你們。
此次重返,依然帶給你們一個小指南,也是最近工做中遇到的一個小case。javascript
前不久,產品經理提出要在界面上優雅地展現PDF文檔,立即就有了兩種實現方式:css
實現方式一
使用embed
標記來使用瀏覽器自帶的pdf工具。html
這種實現方式優缺點都很明顯:
優勢:自帶「打印」,「搜索」,「翻頁」等功能,強大且實現方便。
缺點:不一樣瀏覽器的pdf工具樣式不一,且沒法知足個性化需求,好比:禁止打印,下載等。java
咱們的產品經理是挑剔的😒,因而...git
實現方式二
使用Mozilla的PDF.js
,自定義展現PDF。github
下面咱們就細緻講述一下使用
PDF.js
過程當中遇到的問題。主要包括:
Text-Layers
渲染PDF.js是基於HTML5技術構建的,用於展現可移植文檔格式的文件(PDF),它能夠在現代瀏覽器中使用且無需安裝任何第三方插件。web
1️⃣引用npm
首先,引用PDF.js
就遇到了問題,官網中提到經過CDN引用或者下載源碼至本地。
而咱們並不想污染咱們的index.html
而且但願能夠對每個引用的框架有統一的版本管理。因而,咱們搜尋到一個包:pdfjs-dist。canvas
經過npm install pdfjs-dist
,咱們引入了PDF.js。segmentfault
基礎功能有兩個必須引用的文件:
若是使用CDN的方式,直接引用以下對應文件便可:
若是使用npm的方式,則在須要使用PDF.js的文件中以下引用:
import PDFJS from 'pdfjs-dist'; PDFJS.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker.js';
這兩個文件包含了獲取、解析和展現PDF文檔的方法,可是解析和渲染PDF須要較長的時間,可能會阻塞其它JS代碼的運行。
爲解決該問題,pdf.js依賴了HTML5引入的Web Workers——經過從主線程中移除大量CPU操做(如解析和渲染)來提高性能。
PDF.js的API都會返回一個Promise,使得咱們能夠優雅的處理異步操做。
2️⃣使用
首先,咱們須要在HTML中添加<canvas>
元素以渲染PDF:
<canvas id="pdf-canvas"></canvas>
而後添加渲染PDF的js代碼:
var url = 'Helloworld.pdf'; PDFJS.getDocument(url).then((pdf) => { return pdf.getPage(1); }).then((page) => { // 設置展現比例 var scale = 1.5; // 獲取pdf尺寸 var viewport = page.getViewport(scale); // 獲取須要渲染的元素 var canvas = document.getElementById('pdf-canvas'); var context = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = viewport.width; var renderContext = { canvasContext: context, viewport: viewport }; page.render(renderContext); });
如今,PDF已經成功渲染在界面上了。咱們來分析一下使用到的函數:
getDocument()
:用於異步獲取PDf文檔,發送多個Ajax請求以塊的形式下載文檔。它返回一個Promise,該Promise的成功回調傳遞一個對象,該對象包含PDF文檔的信息,該回調中的代碼將在完成PDf文檔獲取時執行。
getPage()
:用於獲取PDF文檔中的各個頁面。
getViewport()
:針對提供的展現比例,返回PDf文檔的頁面尺寸。
render()
:渲染PDF。
到這裏,基本功能告一段落了。
滿心歡喜準備上線的時候,產品經理提出了另外一個需求:文本複製。
然鵝。。。翻了好幾遍官方文檔,也沒有找到文本複製的方法,而且stackoverflow上有不少相似的問題。
在不斷的嘗試下,咱們發現了Text-Layer
。
PDF.js支持在使用Canvas渲染的PDF頁面上渲染文本圖層。然而,這個功能須要用到額外的兩個文件:text_layer_builder.js
和text_layer_builder.css
。咱們能夠在GitHub的repo中獲取到。
若是是使用npm,則須要作以下引用:
import { TextLayerBuilder } from 'pdfjs-dist/web/pdf_viewer'; import 'pdfjs-dist/web/pdf_viewer.css';
如今,咱們開始實現文本複製功能。
首先,建立渲染須要用到DOM節點:
<div id="container"></div>
div#container
爲最外層節點,在該div中,咱們會爲PDF的每一個頁面建立本身的div
,在每一個頁面的div
中,都會有Canvas
元素。
接着,咱們修改JS代碼:
var container, pageDiv; function getPDF(url) { PDFJS.getDocument(url).then((pdf) => { pdfDoc = pdf; container = document.getElementById('container'); for (var i = 1; i<= pdf.numPages; i++) { renderPDF(i); } }) } function renderPDF(num) { pdf.getPage(num).then((page) => { var scale = 1.5; var viewport = page.getViewport(scale); pageDiv = document.createElement('div'); pageDiv.setAttribute('id', 'page-' + (page.pageIndex + 1)); pageDiv.setAttribute('style', 'position: relative'); container.appendChild(pageDiv); var canvas = document.createElement('canvas'); pageDiv.appendChild(canvas); var context = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = view.width; var renderContext = { canvasContext: context, viewport: viewport }; page.render(renderContext); }); }
以上代碼只是實現了多頁渲染,接下來,開始渲染文本圖層。咱們須要將page.render(renderContext)
修改成如下代碼:
page.render(renderContext).then(() => { return page.getTextContent(); }).then((textContent) => { // 建立文本圖層div const textLayerDiv = document.createElement('div'); textLayerDiv.setAttribute('class', 'textLayer'); // 將文本圖層div添加至每頁pdf的div中 pageDiv.appendChild(textLayerDiv); // 建立新的TextLayerBuilder實例 var textLayer = new TextLayerBuilder({ textLayerDiv: textLayerDiv, pageIndex: page.pageIndex, viewport: viewport }); textLayer.setTextContent(textContent); textLayer.render(); });
咱們依舊來說解如下用到的幾個關鍵函數:
page.render()
:該函數返回一個當PDF頁面成功渲染到界面上時解析的promise
,咱們可使用成功回調來渲染文本圖層。
page.getTextContent()
:該函數的成功回調會返回PDF頁面上的文本片斷。
TextLayerBuilder
:該類的實例有兩個重要的方法。setTextContent()
用於設置page.getTextContent()
函數返回的文本片斷;render()
用於渲染文本圖層。
Bingo😎!經過以上改造,文本複製功能就實現了。官方文檔上可沒有這個小技巧哦。
PDF.js是一個很棒的工具,但無奈文檔寫的較爲精簡,須要開發人員不斷探索PDF.js的強大功能。
若是這篇文章有幫助到您,記得點贊咯👍!