【PDF.js】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/166972.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/166972.shtml
英文地址,請注明出處:http://en.pswp.cn/news/166972.shtml

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

相關文章

flutter與原生Android通信方式之MethodChannel

閑來無事&#xff0c;flutter好久沒看了&#xff0c;上次折騰flutter與Android通信沒折騰完&#xff0c;有些事情耽擱了&#xff0c;這次繼續 演示效果&#xff1a; flutter與Android原生通信 flutter端 import package:flutter/cupertino.dart; import package:flutter/mater…

ThreeJs實現簡單的動畫

上一節實現可用鼠標控制相機的方式實現動態效果&#xff0c;但很多時候是需要場景自己產恒動態效果&#xff0c;而不是通過鼠標拖動&#xff0c;此時引入一個requestAnimationFrame方法&#xff0c;它實際上是通過定時任務的方式&#xff0c;每隔一點時間改變場景中內容后重新渲…

筆記:如何搭建一套前端監控系統?(持續更新中)

數據敏感處理 數據加密&#xff0c;對涉及用戶隱私的數據做到加密防護 獨立部署&#xff0c;不和其它應用共享監控系統 不采集具體數據&#xff0c;只采集用戶操作數據 錯誤采集 Runtime Error: JS運行錯誤&#xff0c;可通過error監聽器捕獲 load Error: 資源加載錯誤&#x…

Ant Design Vue 樹形表格計算盈收金額

樹形表格計算 一、盈收金額計算1、根據需要輸入的子級位置&#xff0c;修改數據2、獲取兄弟節點數據&#xff0c;并計算兄弟節點的金額合計3、金額合計&#xff0c;遍歷給所有的父級 一、盈收金額計算 1、根據需要輸入的子級位置&#xff0c;修改數據 2、獲取兄弟節點數據&am…

銷售管理系統的實用性怎么樣?

銷售管理系統好用嗎&#xff1f;好用&#xff0c;銷售管理系統可以管理銷售流程、自動化大量重復性工作&#xff0c;讓銷售人員從瑣碎的任務中掙脫出來&#xff0c;投入到客戶跟進和維護客戶關系之中。那么&#xff0c;CRM系統的好用體現在哪些方面&#xff1f; 1.加速銷售流程…

react中的state

沒想到hooks中也有state這一說法 看下面的兩個案例 1、無state變化不會執行父子函數 2、有state更改執行父子函數

CDN加速在網站搭建中的必要性與優勢分析

隨著互聯網的快速發展&#xff0c;網站已經成為企業展示和用戶交互的主要平臺。在構建一個高性能、用戶體驗良好的網站時&#xff0c;CDN&#xff08;內容分發網絡&#xff09;的應用變得愈發重要。本文將從網站搭建的角度出發&#xff0c;深入分析CDN加速的必要性以及在提升網…

深度學習之六(自編碼器--Autoencoder)

概念 自編碼器(Autoencoder)是一種神經網絡架構,用于無監督學習和數據的降維表示。它由兩部分組成:編碼器(Encoder)和解碼器(Decoder)。 結構: 編碼器(Encoder): 接收輸入數據并將其壓縮為潛在表示(latent representation),通常比輸入數據的維度要低。編碼器的…

最詳細的軟件測試面試題整理與分析

前言 時光荏苒&#xff0c;一轉眼到了2023年末尾&#xff0c;2024年也快要來了&#xff0c;人員就業市場以往的寒冬也貌似有了轉暖的跡象&#xff0c;身邊大批的就業人員也開始了緊張的備戰之中。 近幾周也和多家合作公司的HR進行了溝通&#xff0c;發現雖然崗位就業情況較去年…

vue3中引入svg矢量圖

vue3中引入svg矢量圖 1、前言2、安裝SVG依賴插件3、在vite.config.ts 中配置插件4、main.ts入口文件導入5、使用svg5.1 在src/assets/icons文件夾下引入svg矢量圖5.2 在src/components目錄下創建一個SvgIcon組件5.3 封裝成全局組件&#xff0c;在src文件夾下創建plugin/index.t…

SQLserver 數據庫導入MySQL的方法

原文&#xff1a; https://blog.csdn.net/lht631935612/article/details/132086172#httpspanbaiducoms1TlLiRI9stxqTcwBJ5p6UAE993BEE68EA5EFBC9Ahttpspanbaiducoms1TlLiRI9stxqTcwBJ5p6UA2020E68F90E58F96E7A081EFBC9Av6d5_font_colordd0000v6d5font_8 下載鏈接&#xff1a;…

使用openfeign調用下載流的文件不完整的替代方案

OpenFeign是一種聲明式的Web服務客戶端&#xff0c;它使得編寫HTTP客戶端變得更加簡單和直觀。它使用了注解方式來描述HTTP API&#xff0c;使得開發者可以使用Java接口來調用遠程HTTP服務。 OpenFeign的核心特點包括&#xff1a; 聲明式API: 您可以使用注解聲明要調用的遠程AP…

一鍵創新 | 拓世法寶AI智能直播一體機激發房產自媒體創造力

在數字化時代&#xff0c;房產銷售已然不再是傳統的模式。隨著社交媒體和自媒體的興起&#xff0c;短視頻直播成為房產自媒體營銷的新風口。然而&#xff0c;行業也面臨著諸多挑戰&#xff0c;如何更好地利用新媒體拓展市場&#xff0c;提升自媒體效果成為擺在業內人士面前的難…

JMeter測試報錯422 Unprocessable Entity

添加HTTP信息頭&#xff1a; ? HTTP請求-》添加-〉配置元件-》HTTP信息頭管理器 ? 如果需要送json&#xff0c;需要添加Content-Type:application/json&#xff0c;否則會報【422 Unprocessable Entity】

好用的CRM系統到底有多重要?怎么選?

我們都知道&#xff0c;CRM軟件可以讓企業效率加倍。但如果選錯了CRM&#xff0c;企業損失點錢是小&#xff0c;客戶轉化率下降才是大。下面我們就來說說&#xff0c;市面上有哪些好用的CRM&#xff1f;以及好用的CRM軟件的重要性。 好用的CRM軟件的重要性&#xff1a; 客戶管…

Qt 軟件調試(一) Log日志調試

終于這段時間閑下來了&#xff0c;可以系統的編寫Qt軟件調試的整個系列。前面零零星星的也有部分輸出&#xff0c;但終究沒有形成體系。借此機會&#xff0c;做一下系統的總結。慎獨、精進~ 日志是有效幫助我們快速定位&#xff0c;找到程序異常點的實用方法。但是好的日志才能…

百度 文心一言 sdk 試用

JMaven Central: com.baidu.aip:java-sdk (sonatype.com) Java sdk地址如上&#xff1a; 文心一言開發者 文心一言 (baidu.com) ERNIE Bot SDK https://yiyan.baidu.com/developer/doc#Fllzznonw ERNIE Bot SDK提供便捷易用的接口&#xff0c;可以調用文心一言的能力&#…

口袋參謀:如何避免寶貝被降權?這招屢試屢爽!

?至少99.99999%的店鋪在今年都被降權過&#xff01;各家店鋪被降權的原因&#xff0c;無非就一個原因&#xff0c;那就是s單&#xff01; s單的風險也就兩種&#xff0c;一是操作問題&#xff0c;二是賬號問題。 操作問題被降權&#xff0c;這個大家都心知肚明&#xff0c;s…

5大原因,設備校準為什么是實驗室搬遷后的首要任務?

實驗室搬遷是一個復雜而緊張的過程。要考慮的事情太多&#xff0c;很容易忽視您最重要的任務之一——檢查設備在新環境中的性能。 校準對于確保設備安全運行和遵守監管標準至關重要。 1.保持合規性并遵守法律要求 生物技術和制藥等行業有特定的校準要求&#xff0c;實驗室必…

Java詳解之I/O[BIO、NIO、AIO使用方法和示范代碼]

前言&#xff1a; 小弟能力不足&#xff0c;認知有限&#xff0c;難免考慮不全面&#xff0c;希望大佬能給出更好的建議&#xff0c;指出存在的問題和不足&#xff0c;在此跪謝。 IO發展史 Java中對于I/O能力的支持主要分為三個比較關鍵的階段&#xff1a; BIO 第一個階段…