本文經Vildan Softic同行評審。感謝所有SitePoint的同行評審員,讓SitePoint的內容達到最佳狀態!
在Web應用程序中處理PDF文件一直以來都非常棘手。如果幸運的話,你的用戶只需要下載文件即可。但有時,用戶需要更多功能。過去,我比較幸運,但這次,我們的用戶需要應用程序顯示PDF文檔,以便他們可以保存與每個頁面相關的元數據。以前,人們可能使用昂貴的PDF插件(例如Adobe Reader)在瀏覽器中運行來實現此目的。然而,經過一番時間和實驗,我找到了一種更好的方法來在Web應用程序中集成PDF查看器。今天,我們將了解如何使用Aurelia和PDF.js簡化PDF處理。
我們今天的目標是在Aurelia中構建一個PDF查看器組件,允許查看器和我們的應用程序之間進行雙向數據流。我們有三個主要要求:
您可以在我們的GitHub倉庫中找到本教程的代碼,以及此處完成代碼的演示。
PDF.js是一個由Mozilla基金會編寫的JavaScript庫。它加載PDF文檔,解析文件和相關的元數據,並將頁面輸出渲染到DOM節點(通常是<canvas></canvas>
元素)。項目中包含的默認查看器為Chrome和Firefox中的嵌入式PDF查看器提供支持,可以用作獨立頁面或資源(嵌入在iframe中)。
這確實很酷。這裡的問題是,默認查看器雖然有很多功能,但它被設計為一個獨立的網頁。這意味著,雖然它可以集成到Web應用程序中,但它基本上必須在iframe沙箱內運行。默認查看器設計為通過其查詢字符串獲取配置輸入,但是我們不能在初始加載後輕鬆更改配置,也不能輕鬆地從查看器獲取信息和事件。為了將其與Aurelia Web應用程序集成——包括事件處理和雙向綁定——我們需要創建一個Aurelia自定義組件。
注意:如果您需要關於PDF.js的複習,請查看我們的教程:使用Mozilla的PDF.js在JavaScript中進行自定義PDF渲染
為了實現我們的目標,我們將創建一個Aurelia自定義元素。但是,我們不會將默認查看器放入我們的組件中。相反,我們將創建自己的查看器,它連接到PDF.js核心和查看器庫,以便我們可以最大限度地控制我們的可綁定屬性和渲染。對於我們的初始概念驗證,我們將從Aurelia骨架應用程序開始。
樣板代碼
正如您從上面的鏈接中看到的那樣,骨架應用程序有很多文件,其中許多文件我們不需要。為了簡化操作,我們準備了一個精簡版本的骨架,並在其中添加了一些內容:
所以讓我們啟動並運行應用程序。
首先,確保全局安裝了gulp和jspm:
npm install -g gulp jspm
然後克隆骨架並進入其中:
git clone git@github.com:sitepoint-editors/aurelia-pdfjs.git -b skeleton cd aurelia-pdfjs
然後安裝必要的依賴項:
npm install jspm install -y
最後運行gulp watch並導航到http://localhost:9000。如果一切按計劃進行,您應該會看到一條歡迎消息。
更多設置
接下來要做的是找到幾個PDF文件並將它們放在src/documents中。將它們命名為one.pdf和two.pdf。為了最大限度地測試我們的自定義組件,最好其中一個PDF文件非常長,例如可以在古騰堡計劃中找到的《戰爭與和平》。
將PDF文件放在適當位置後,打開src/app.html和src/app.js(按照約定,App組件是Aurelia應用程序的根組件),並將其中的代碼替換為這兩個文件的代碼:src/app.html和src/app.js。在本教程中,我們將不會討論這些文件,但代碼中有很好的註釋。
Gulp將自動檢測這些更改,您應該會看到我們的應用程序UI呈現。設置就是這樣。現在開始展示……
我們希望創建一個可以直接用於任何Aurelia視圖的組件。由於Aurelia視圖只是一個包含在HTML5模板標籤中的HTML片段,因此一個示例可能如下所示:
npm install -g gulp jspm
<pdf-document>
標籤是自定義元素的一個示例。它及其屬性(如scale和page)不是HTML的原生屬性,但我們可以使用Aurelia自定義元素來創建它。自定義元素易於創建,使用Aurelia的基本構建塊:視圖和ViewModel。因此,我們將首先搭建我們的ViewModel,命名為pdf-document.js,如下所示:
git clone git@github.com:sitepoint-editors/aurelia-pdfjs.git -b skeleton cd aurelia-pdfjs
這裡要注意的主要內容是@bindable
裝飾器;通過創建具有配置defaultBindingMode: bindingMode.twoWay
的可綁定屬性,並通過在我們的ViewModel中創建處理程序方法(urlChanged、pageChanged等),我們可以監控和響應我們放置在自定義元素上的相關屬性的更改。這將允許我們簡單地通過更改元素上的屬性來控制我們的PDF查看器。
然後,我們將創建與我們的ViewModel配對的初始視圖。
npm install jspm install -y
(以下內容與原文基本一致,只是對部分語句進行了細微的調整,以保持流暢性和可讀性,並避免重複。)
PDF.js分為三個部分:核心庫(處理PDF文檔的解析和解釋)、顯示庫(在核心層之上構建可用的API)以及Web查看器插件(我們前面提到的預構建網頁)。出於我們的目的,我們將通過顯示API使用核心庫;我們將構建我們自己的查看器。
顯示API導出一個名為PDFJS的庫對象,它允許我們設置一些配置變量並使用PDFJS.getDocument(url)加載我們的文檔。該API是完全異步的——它向Web Worker發送和接收消息,因此它大量依賴於JavaScript Promise。我們將主要使用從PDFJS.getDocument()方法異步返回的PDFDocumentProxy對象和從PDFDocumentProxy.getPage()異步返回的PDFPageProxy對象。
儘管文檔有點稀疏,但PDF.js有一些創建基本查看器的示例,這里和這裡。我們將以此為基礎構建我們的自定義組件。
Web Worker集成
PDF.js使用Web Worker來卸載其渲染任務。由於Web Worker在瀏覽器環境中的運行方式(它們實際上是沙箱化的),我們被迫使用JavaScript文件的直接文件路徑來加載Web Worker,而不是通常的模塊加載器。幸運的是,Aurelia提供了一個加載器抽象,因此我們不必引用靜態文件路徑(當我們捆綁應用程序時,這可能會發生變化)。
如果您正在關注我們版本的倉庫,您可能已經安裝了pdfjs-dist包,否則,您現在需要這樣做(例如,使用jspm jspm install npm:pdfjs-dist@^1.5.391)。然後,我們將使用Aurelia的依賴注入模塊注入Aurelia的加載器抽象,並使用加載器在我們的構造函數中加載Web Worker文件,如下所示:
加載頁面
PDF.js庫處理PDF文檔的加載、解析和顯示。它具有對部分下載和身份驗證的內置支持。我們所要做的就是提供相關文檔的URI,PDF.js將返回一個Promise對象,該對象解析為表示PDF文檔及其元數據的JavaScript對象。
PDF的加載和顯示將由我們的可綁定屬性驅動;在這種情況下,它將是url屬性。基本上,當URL更改時,自定義元素應該要求PDF.js發出對文件的請求。我們將在urlChanged處理程序中執行此操作,並對我們的構造函數進行一些更改以初始化一些屬性,並對我們的detached方法進行一些更改以進行清理。
對於文檔的每一頁,我們將在DOM中創建一個<canvas></canvas>
元素,該元素位於具有固定高度的可滾動容器內。為此,我們將使用Aurelia的基本模板功能,使用一個repeater。因為每個PDF頁面都可以有自己的大小和方向,所以我們將根據PDF頁面視口設置每個canvas元素的寬度和高度。
渲染頁面
現在我們已經加載了頁面,我們需要能夠將它們渲染到DOM元素。為此,我們將依賴於PDF.js的渲染功能。 PDF.js查看器庫有一個專門用於渲染頁面的異步API;他們的網站上有一個很好的示例,展示瞭如何創建一個renderContext對象並將其傳遞給PDF.js渲染方法。我們將這段代碼從示例中提取出來,並將其包裝在一個render函數中:
實現滾動
為了提供熟悉且無縫的體驗,我們的組件應該將頁面顯示為完全可滾動文檔的各個部分。我們可以通過使我們的容器具有具有滾動溢出的固定高度來實現這一點,這可以通過CSS來實現。
為了最大限度地提高大型文檔的性能,我們將執行以下幾件事。首先,我們將利用Aurelia的TaskQueue來批量更改DOM。其次,我們將跟踪PDF.js已經渲染的頁面,這樣它就不必重做它已經完成的工作。最後,我們將只在滾動停止後渲染可見頁面,方法是使用Aurelia的debounce綁定行為。這是我們在滾動時將運行的方法:
實現縮放
當我們縮放時,我們希望更新當前縮放級別。我們將在scaleChanged屬性處理程序中執行此操作。基本上,我們將調整所有canvas元素的大小以反映給定比例的每一頁的新視口大小。然後,我們將重新渲染當前視口中顯示的內容,重新啟動循環。
最終結果
讓我們回顧一下我們的目標:
最終代碼可以在我們的GitHub倉庫中找到,以及此處完成代碼的演示。雖然仍有改進的空間,但我們已經達到了目標!
(以下內容與原文基本一致,只是對部分語句進行了細微的調整,以保持流暢性和可讀性,並避免重複。)
總有改進的空間,進行項目後分析並確定未來迭代中需要解決的領域始終是一個好習慣。以下是一些我想在PDF查看器實現方面進行升級的內容:
Aurelia提供了一個插件系統。將這個概念驗證轉換為Aurelia插件將使其成為任何Aurelia應用程序的即用型資源。 Aurelia Github倉庫提供了一個插件骨架項目,這將是一個良好的起點。這樣,其他人就可以使用此功能,而無需重新構建它!
在Web應用程序中處理PDF文件一直以來都非常棘手。但是,憑藉當今可用的資源,我們可以通過組合庫及其功能來實現比以往更多的事情。今天,我們已經看到一個基本PDF查看器的示例——一個可以通過自定義功能擴展的查看器,因為我們可以完全控制它。可能性是無限的!你準備好構建一些東西了嗎?請在下面的評論中告訴我。
(以下內容與原文基本一致,只是對部分語句進行了細微的調整,以保持流暢性和可讀性,並避免重複。)
以上是Aurelia的冒險:創建自定義PDF查看器的詳細內容。更多資訊請關注PHP中文網其他相關文章!