2023 最新 PDF.js 在 Vue3 中的使用

因為自己寫業務要定制各種 pdf 預覽情況(可能),所以采用了 pdf.js 而不是各種第三方封裝庫,主要還是為了更好的自由度。

一、PDF.js 介紹

官方地址
中文文檔

PDF.js 是一個使用 HTML5 構建的便攜式文檔格式查看器。
pdf.js 是社區驅動的,并由 Mozilla 支持。我們的目標是為解析和呈現 PDF 創建一個通用的、基于 Web 標準的平臺。

二、 安裝方法

1、下載 pdf.js

下載地址
在這里插入圖片描述
我下載的版本是 pdfjs-4.0.189-dist
在這里插入圖片描述

2、解壓包并放到項目中

解壓后將完整文件夾放到 vue3 的 public 文件夾內
在這里插入圖片描述

3、屏蔽跨域錯誤,允許跨域

web/viewer.mjs 內找到搜索 throw new Error("file origin does not match viewer's") 并注釋掉,如果不注釋,可能會出現跨域錯誤,無法正常預覽文件
在這里插入圖片描述
這樣就算安裝完成了,后面我們開始在項目中使用。

三、基礎使用

1、創建 PDF 組件

我們可以創建一個 PDF 組件,代碼如下:

<script setup lang="ts">
import { onMounted, ref } from 'vue';
interface Props {url: string; // pdf文件地址
}
const props = defineProps<Props>();
const pdfUrl = ref(''); // pdf文件地址
const fileUrl = '/pdfjs-4.0.189-dist/web/viewer.html?file='; // pdfjs文件地址onMounted(() => {// encodeURIComponent() 函數可把字符串作為 URI 組件進行編碼。// 核心就是將 iframe 的 src 屬性設置為 pdfjs 的地址,然后將 pdf 文件的地址作為參數傳遞給 pdfjs// 例如:http://localhost:8080/pdfjs-4.0.189-dist/web/viewer.html?file=http%3A%2F%2Flocalhost%3A8080%2Fpdf%2Ftest.pdfpdfUrl.value = fileUrl + encodeURIComponent(props.url);
});
</script><template><div class="container"><iframe :src="pdfUrl" width="100%" height="100%"></iframe></div>
</template><style scoped lang="scss">
.container {width: 100%;height: 100%;
}
</style>

2、使用組件

比如我們需要預覽 public 下的一個 test.pdf 文件

<div class="pdf-box"><PDF url="/public/test.pdf" />
</div>

下面是界面默認預覽效果
在這里插入圖片描述

四、進階使用

1、頁面跳轉(傳參)

比如我們要跳到第 10 頁,我們可以在地址里面添加參數 &page=${10}

pdfUrl.value = fileUrl + encodeURIComponent(props.url) + `&page=${10}`;

viewer.mjs 找到 setInitialView 函數,注意是下面這個:
在這里插入圖片描述
重點:在函數末尾最下面添加下面的跳轉代碼(寫在上面會報錯,因為還沒有獲取到實例)

    console.log(this.pdfViewer);// 獲取url參數function getQueryVariable(variable) {var query = window.location.search.substring(1);var vars = query.split('&');for (var i = 0; i < vars.length; i++) {var pair = vars[i].split('=');if (pair[0] == variable) {return pair[1];}}return false;}// 跳轉到指定頁const page = getQueryVariable('page');console.log(page);if (page) {this.pdfViewer.currentPageNumber = Number(page);}

2、文本標注(傳參)

某些時候我們需要跳轉到指定頁面,然后自動標注文本,這個時候就需要自動標注了
在這里插入圖片描述
代碼跟跳轉一樣,寫在后面就可以了

    // 自動高亮文本(要解碼)decodeURIComponent: 解碼const markText = decodeURIComponent(getQueryVariable('markText'));console.log('markText===>', markText);if (markText) {// 對查詢輸入框進行賦值document.getElementById('findInput').value = markText;// 點擊高亮按鈕實現高亮顯示關鍵詞document.getElementById('findHighlightAll').click();}

目前我還沒有找到批量標注的辦法,批量標注建議還是使用下面頁面+坐標,遮罩的方法
在這里插入圖片描述

3、添加遮罩高亮(頁碼+坐標)

主要是為了解決批量標注的問題,因為 pdfjs 原生只支持單文本,不支持批量,要修改大量源碼(我能力不行,太難了😥)

所以還是換了種方案,就是后端返回頁碼+坐標,添加遮罩層渲染的方式。

這種方法主要是找到渲染的 dom元素,因為渲染的pdf有一個叫做 data-page-number="1" 的屬性,因此我們可以通過 js 的 querySelectorAll 選擇器找到對應屬性的 dom 元素,然后再操作添加遮罩就可以了,代碼放在下面。
在這里插入圖片描述

    // 測試的坐標const content_pos_1 = {x: 0.5135954145019941,y: 0.4662730487881233,};const content_pos_2 = {x: 0.7135954145019941,y: 0.8662730487881233,};// 查找屬性 data-page-number='頁碼' 的 dom 元素const pageList = document.querySelectorAll(`[data-page-number='${page}']`);console.log('查詢到的dom列表===>\n', pageList[1]);// 查詢到的第一個是左側小菜單頁碼div,第二個是才是展示的divconst pageView = pageList[1];console.log('右側展示的dom===>\n', pageView);// 在元素上畫一個divconst div = document.createElement('div');div.style.width = (content_pos_2.x - content_pos_1.x) * 100 + '%';div.style.height = (content_pos_2.y - content_pos_1.y) * 100 + '%';div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = content_pos_1.y * 100 + '%';div.style.left = content_pos_1.x * 100 + '%';div.style.zIndex = '1'; // pdfjs 文本的層級是2 所以這里要設置為1 放著不能復制pageView.appendChild(div);

渲染到pdf上就是下面的樣子:
在這里插入圖片描述

4、添加遮罩高亮(縮放動態更新)

因為 pdf 會縮放的緣故,縮放的話會重新更新 pdf ,我們添加的 div 就會消失,所以我們要在重新更新的時候重新添加,源碼內部重新添加的函數在這個位置: #updateUIState
在這里插入圖片描述
我們只需要將修改后重新添加的代碼放在尾部就行
首先我們要修改第三部分的代碼

   // 測試的坐標const content_pos_1 = {x: 0.5135954145019941,y: 0.4662730487881233,};const content_pos_2 = {x: 0.7135954145019941,y: 0.8662730487881233,};// pdf 縮放會重新設置,所以放在window保存,其他地方要用window.page = page;window.shade = {width: (content_pos_2.x - content_pos_1.x) * 100 + '%',height: (content_pos_2.y - content_pos_1.y) * 100 + '%',top: content_pos_1.y * 100 + '%',left: content_pos_1.x * 100 + '%',};console.log(window.shade);// 查找屬性 data-page-number='頁碼' 的 dom 元素const pageList = document.querySelectorAll(`[data-page-number='${page}']`);console.log('查詢到的dom列表===>\n', pageList[1]);// 查詢到的第一個是左側小菜單頁碼div,第二個是才是展示的divconst pageView = pageList[1];console.log('右側展示的dom===>\n', pageView);// 在元素上畫一個divconst div = document.createElement('div');div.id = 'shade';div.style.width = window.shade.width;div.style.height = window.shade.height;div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = window.shade.top;div.style.left = window.shade.left;div.style.zIndex = '1';pageView.appendChild(div);

然后在 #updateUIState 函數的末尾添加下面的新增代碼

    setTimeout(() => {if (!window.page) return;const pageList = document.querySelectorAll(`[data-page-number='${window.page}']`);const pageView = pageList[1];// 刪除 id 為 shade 的元素(舊遮罩)const shade = document.getElementById('shade');if (shade) {shade.remove();}const div = document.createElement('div');div.id = 'shade';div.style.width = window.shade.width;div.style.height = window.shade.height;div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = window.shade.top;div.style.left = window.shade.left;div.style.zIndex = '1';pageView.appendChild(div);}, 500);

最終效果如下:
在這里插入圖片描述
ps:如果要做大量的頁面+坐標渲染(后端返回的是個數組),修改下上面的代碼邏輯就行,傳參自己寫,不難的

當然,也可以看下面的代碼哈哈哈,我還是寫出來吧

5、添加遮罩高亮(數組批量跨頁渲染)

假設后端返回的數據格式是這樣的,是一個包含 頁碼、坐標的標注數組,我們需要在每個頁碼內渲染遮罩
在這里插入圖片描述

我們就需要這樣傳參
在這里插入圖片描述
setInitialView(storedHash, { rotation, sidebarView, scrollMode, spreadMode } = {}) 初始化函數中:

    window.content_pos = JSON.parse(decodeURIComponent(getQueryVariable('content_pos')));console.log(window.content_pos[0]);window.content_pos.forEach((item, index) => {const page = item.page_no;const shade = {width: (item.right_bottom.x - item.left_top.x) * 100 + '%',height: (item.right_bottom.y - item.left_top.y) * 100 + '%',top: item.left_top.y * 100 + '%',left: item.left_top.x * 100 + '%',};console.log(shade);const pageList = document.querySelectorAll(`[data-page-number='${page}']`);const pageView = pageList[1];const div = document.createElement('div');div.id = 'shade' + index;div.style.width = shade.width;div.style.height = shade.height;div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = shade.top;div.style.left = shade.left;div.style.zIndex = '1';pageView.appendChild(div);});

#updateUIState(resetNumPages = false) 更新函數中:

    setTimeout(() => {if (window.content_pos) {window.content_pos.forEach((item, index) => {const shadeEl = document.getElementById('shade' + index);if (shadeEl) {shadeEl.remove();}const page = item.page_no;const shade = {width: (item.right_bottom.x - item.left_top.x) * 100 + '%',height: (item.right_bottom.y - item.left_top.y) * 100 + '%',top: item.left_top.y * 100 + '%',left: item.left_top.x * 100 + '%',};const pageList = document.querySelectorAll(`[data-page-number='${page}']`);const pageView = pageList[1];const div = document.createElement('div');div.id = 'shade' + index;div.style.width = shade.width;div.style.height = shade.height;div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = shade.top;div.style.left = shade.left;div.style.zIndex = '1';pageView.appendChild(div);});}}, 500);

效果展示,可以實現跨頁,多頁渲染
在這里插入圖片描述

后續根據開發業務持續更新😁

感謝大佬們的無私分享

詳細|vue中使用PDF.js預覽文件實踐
vue3項目使用pdf.js插件實現:搜索高亮、修改pdf.js顯示的頁碼、向pdf.js傳值、控制搜索、處理接口文件流
pdf.js根據路徑里傳參數高亮顯示關鍵字(跳轉到對應頁面)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/167901.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/167901.shtml
英文地址,請注明出處:http://en.pswp.cn/news/167901.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

人工智能教程(二):人工智能的歷史以及再探矩陣

目錄 前言 更多矩陣的知識 Pandas 矩陣的秩 前言 在上一章中&#xff0c;我們討論了人工智能、機器學習、深度學習、數據科學等領域的關聯和區別。我們還就整個系列將使用的編程語言、工具等做出了一些艱難的選擇。最后&#xff0c;我們還介紹了一點矩陣的知識。在本文中&am…

vue打包上傳服務器的總結筆記

經歷了3個小時教訓&#xff0c;還是自己總結一下吧&#xff0c;致未來傻x的自己。 第一步&#xff0c;打開b站。搜索【vue打包】找到一個視頻教程 前端Vue項目打包部署實戰教程_嗶哩嗶哩_bilibili 這步是在看不懂下面操作的情況下用的 第一步&#xff1a;找到nginx的配置文件…

需求變更導致估算不精準 6大措施

需求變更可能導致估算不精準、項目成本增加、進度延遲等問題&#xff0c;如果不能準確地估算項目&#xff0c;往往會造成資源浪費和開發效率的降低&#xff0c;因此亟需解決因需求變更導致地估算不精準的問題。 一般來說&#xff0c;主要是從以下6個方面入手解決&#xff1a; 1…

【maven】【IDEA】idea中使用maven編譯項目,報錯java: 錯誤: 找不到符號 【2】

idea中使用maven編譯項目,報錯java: 錯誤: 找不到符號 錯誤狀況展示: 如果報這種錯,是因為項目中真的找不到報錯的方法或者枚舉 字段之類的,但實際是 : 點擊 File Path

OSG粒子系統與陰影-霧效模擬(1)

虛擬現實中有很多效果&#xff0c;如雨效、雪效、霧效等&#xff0c;這些都可以通過粒子系統來實現。一個真實的粒子系統的模式能使三維場景達到更好的效果。 本章對OSG粒子系統的使用以及生成自定義粒子系統的方法進行了詳細介紹最后還附帶說明了陰影的使用方法。在實時的場景…

(HAL庫版)freeRTOS移植STMF103

正點原子關于freeRTOS的教程是比較好的&#xff0c;可惜移植的是標準庫&#xff0c;但是我學的是Hal庫&#xff0c;因為開發速度更快&#xff0c;從最后那個修改SYSTEM文件夾的地方開始替換為下面的內容就可以了 5.修改Systick中斷、SVC中斷、PendSV中斷 將SVC中斷、P…

pairplot

Python可視化 | Seaborn5分鐘入門(七)——pairplot - 知乎 (zhihu.com) Seaborn是基于matplotlib的Python可視化庫。它提供了一個高級界面來繪制有吸引力的統計圖形。Seaborn其實是在matplotlib的基礎上進行了更高級的API封裝&#xff0c;從而使得作圖更加容易&#xff0c;不需…

紅黑樹詳解

紅黑樹的概念與性質 前置知識 在學習紅黑樹之前&#xff0c;最好有二叉查找樹和AVL樹的基礎&#xff0c;因為紅黑樹本質就是一種特殊的二叉查找樹&#xff0c;而紅黑樹的操作中需要用到AVL樹中旋轉的相關知識。至于二叉查找樹和AVL樹&#xff0c;可以參考如下兩篇博客&#xf…

oracle安裝的肘腋之疾小合集

#臨時空間指定 export TMP/tmp export TMPDIR/tmp #圖形化顯示框不全 java問題&#xff0c;使用系統自帶的jre ./runInstaller -jreLoc/usr/local/jdk1.7.0_80/ #ins30131 Failed to access the temporary location 給/tmp/CVU*加x權限 #linux桌面太小 xrandr -s 1440x900_60…

Matplotlib圖形注釋_Python數據分析與可視化

Matplotlib圖形注釋 添加注釋文字、坐標變換 有的時候單單使用圖形無法完整清晰的表達我們的信息&#xff0c;我們還需要進行文字進行注釋&#xff0c;所以matplotlib提供了文字、箭頭等注釋可以突出圖形中重點信息。 添加注釋 為了使我們的可視化圖形讓人更加容易理解&#…

vue中父組件直接調用子組件方法

vue2 中&#xff0c;父組件如何調用子組件的方法 在Vue 2中&#xff0c;父組件可以通過使用ref屬性來引用子組件的實例&#xff0c;然后通過該實例調用子組件的方法。 首先&#xff0c;在父組件的模板中&#xff0c;給子組件添加一個ref屬性&#xff1a; <template>&l…

在工業生產環境下,服務器沒有互聯網,如何通過代理自己的電腦上互聯網?

服務器主機是CentOS7操作系統.&#xff0c;服務器的局域網是10.0.6.x網段。我的筆記本的以太網口的局域網ip是也是10.0.6.x&#xff0c;由于這個10.0.6.x的整個局域網是沒有撥號上網的所有無法訪問互聯網。 但是&#xff0c;如果筆記本臉上wifi&#xff0c;wifi的網段是192.168…

長度最小的子數組

給定一個含有 n 個正整數的數組和一個正整數 target 。 找出該數組中滿足其總和大于等于 target 的長度最小的 連續子數組 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其長度。如果不存在符合條件的子數組&#xff0c;返回 0 。 示例 1&#xff1a; 輸入&#x…

MySQL 有多個普通索引時會取哪一個索引?

我們都知道MySQL在查詢時底層會進行索引的優化&#xff0c;假設有兩個普通索引&#xff0c;且where 后面也根據這兩個普通索引查詢數據&#xff0c;那么執行查詢語句時會使用到那個索引&#xff1f; 為了方便演示&#xff0c;新建users表&#xff0c;新建idx_name、idx_city這兩…

前端vue導出PPT,使用pptxgen.js

前言 公司新需求需要導出ppt給業務用&#xff0c;查閱資料后發現也挺簡單的&#xff0c;記錄一下。 如有不懂的可以留言&#xff01;&#xff01;&#xff01; 1.安裝包 npm install pptxgenjs --save2.引入包 在需要使用的文件中引入 import Pptxgenfrom "pptxgenjs&…

Oracle研學-介紹及安裝

一 ORACLE數據庫特點: 支持多用戶&#xff0c;大事務量的事務處理數據安全性和完整性控制支持分布式數據處理可移植性(跨平臺&#xff0c;linux轉Windows) 二 ORACLE體系結構 數據庫&#xff1a;oracle是一個全局數據庫&#xff0c;一個數據庫可以有多個實例&#xff0c;每個…

nodejs+vue+python+PHP+微信小程序-留學信息查詢系統的設計與實現-安卓-計算機畢業設計

1、用戶模塊&#xff1a; 1&#xff09;登錄&#xff1a;用戶注冊登錄賬號。 2&#xff09;留學查詢模塊&#xff1a;查詢學校的入學申請條件、申請日期、政策變動等。 3&#xff09;院校排名&#xff1a;查詢國外各院校的實力排名。 4&#xff09;測試功能&#xff1a;通過入學…

Spring Boot WebSocket 客戶端

介紹 WebSocket 是一種在單個 TCP 連接上進行全雙工通信的協議&#xff0c;它可以提供實時的、雙向的數據傳輸。Spring Boot 提供了對 WebSocket 的支持&#xff0c;我們可以使用 Spring Boot WebSocket 客戶端來連接到 WebSocket 服務器&#xff0c;并進行實時通信。 本文將…

python-選擇排序

選擇排序是一種簡單直觀的排序算法&#xff0c;它的基本思想是每一輪選擇未排序部分的最小元素&#xff0c;然后將其放到已排序部分的末尾。這個過程持續進行&#xff0c;直到整個數組排序完成。(重點&#xff1a;通過位置找元素) 以下是選擇排序的詳細步驟和 Python 實現&…

HarmonyOS應用開發實戰—登錄頁面【ArkTS】

文章目錄 本頁面實戰效果預覽圖一.HarmonyOS應用開發1.1HarmonyOS 詳解1.2 ArkTS詳解二.HarmonyOS應用開發實戰—登錄頁面【ArkTS】2.1 ArkTS頁面源碼2.2 代碼解析2.3 心得本頁面實戰效果預覽圖 一.HarmonyOS應用開發 1.1HarmonyOS 詳解 HarmonyOS(鴻蒙操作系統)是華為公司…