前端-選中pdf中的文字并使用,顯示一個懸浮的翻譯按鈕(本地pdfjs+iframe)不適用textlayer

使用pdfjs移步–

vue2使用pdfjs-dist實現pdf預覽(iframe形式,不修改pdfjs原來的ui和控件,dom層可以用display去掉一部分組件)

方案1:獲取選擇文本內容的最前面的字符坐標的位置(這種寫法會導致如果選擇超出pdf容器的高度之后,導致按鈕顯示不出來,這種方法顯示位置固定)

方案2:獲取選擇文本最后鼠標離開位置的坐標(目前沒發現bug,這種方法顯示的位置不固定)這個方法在最下面,核心位置計算方法handleTextSelectionPdf,updateToolPositionPdf

  1. 實現案例
    在這里插入圖片描述
  2. pdf容器創建,懸浮盒子創建
	<iframe:src="pdfurl"class="pdfContent"ref="pdfViewer"frameborder="0"width="100%"height="850px"></iframe><divv-show="selectionToolsVisible"class="selection-tools":style="selectionPosition"@mousedown.prevent><div class="tool-item" @click.stop="getAihelper('entocn')"><img src="../../assets/detailImage/enToCn.png" alt="" /><span class="tool-text">翻譯</span></div></div>
  1. data實例
	data() {return {selectionToolsVisible: false,selectionPosition: { top: '0px', left: '0px' },selectionTimer: null,};},
  1. mounted注冊鼠標事件-注冊pdf的監聽
	this.$refs.pdfViewer.onload = () => {const iframeDoc =this.$refs.pdfViewer.contentDocument ||this.$refs.pdfViewer.contentWindow.document;iframeDoc.addEventListener('mouseup', this.handleTextSelectionPdf);};
  1. pdf監聽代碼-方案1
		handleTextSelectionPdf(e) {clearTimeout(this.selectionTimer);// 緩存關鍵事件屬性const targetElement = e?.target || document.activeElement;// const cachedSelection = window.getSelection().toString().trim();this.selectionTimer = setTimeout(() => {const selection =this.$refs.pdfViewer.contentWindow.getSelection();// 增強型六重驗證const isValid =selection.rangeCount > 0 &&!selection.isCollapsed &&selection.toString().trim().length >= 1 && // 允許單字符選擇targetElement.closest('#viewerContainer');if (isValid) {// console.log(selection);const range = selection.getRangeAt(0);const rect = this.getAdjustedRectPdf(range);this.updateToolPositionPdf(rect);this.selectionToolsVisible = true;this.tempSelection = selection.toString();} else {this.selectionToolsVisible = false;}}, 50); // 優化響應時間},getAdjustedRectPdf(range) {const tempSpan = document.createElement('span');range.insertNode(tempSpan);const rect = tempSpan.getBoundingClientRect();tempSpan.remove();// 獲取 iframe 在整個頁面中的位置const iframeRect = this.$refs.pdfViewer.getBoundingClientRect();// **修正點:確保 top 計算正確**const absoluteTop = rect.top + iframeRect.top;const absoluteLeft = rect.left + iframeRect.left + window.scrollX;// console.log(`iframeRect:`, iframeRect);// console.log(`selection rect:`, rect);// console.log(// 	`absoluteTop: ${absoluteTop}, absoluteLeft: ${absoluteLeft}`// );return {top: absoluteTop,left: absoluteLeft,width: rect.width,height: rect.height,};},updateToolPositionPdf(rect) {const viewportWidth = window.innerWidth;const tooltipWidth = '';this.selectionPosition = {top: `${rect.top - 70}px`,left: `${Math.min(Math.max(rect.left, 10),viewportWidth - tooltipWidth - 10)}px`,maxWidth: `${tooltipWidth}px`,};// console.log(`Final tooltip position:`, this.selectionPosition);},
  1. 部分樣式-按鈕樣式
<style scoped lang="less">
::v-deep .selection-tools {position: fixed;background: rgba(29, 115, 232, 1);border-radius: 5px;box-shadow: 0 4px 12px rgba(25, 118, 210, 0.15);padding: 8px;display: inline-flex;align-items: center;// gap: 6px;z-index: 9999;// opacity: 0;transform: translateY(-10px) scale(0.95);transition: all 0.1s cubic-bezier(0.4, 0, 0.2, 1);/* 移除默認的pointer-events限制 */pointer-events: auto !important;/* 修正激活狀態邏輯 */&::after {content: '';position: absolute;bottom: -11px;left: 50%;transform: translateX(-50%);border: 6px solid transparent;border-top-color: #1d73e8;filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));}&.active {opacity: 1;transform: translateY(0) scale(1);}.tool-item {padding: 6px 12px;border-radius: 4px;cursor: pointer;display: flex;align-items: center;transition: all 0.2s;flex-direction: column;height: 50px;justify-content: space-between;// &:hover {// 	background: #f0f6ff;// 	transform: translateY(-1px);// 	.iconfont {// 		color: #0065cc;// 	}// 	.tool-text {// 		color: #003d82;// 	}// }.tool-text {font-family: Microsoft YaHei;font-weight: 400;font-size: 12px;color: #ffffff;// line-height: 41px;}}.tool-divider {width: 1px;height: 38px;background: #3f86dd;margin: 0 4px;}img {max-width: 24px;}
}
</style>

以上方法可能導致的問題就是如果選擇內容超出了pdf框,會導致按鈕顯示不出來,所以改為選擇之后的鼠標最后出現的位置上面,修改代碼handleTextSelectionPdf,updateToolPositionPdf

pdf位置計算核心方法-方案2

	handleTextSelectionPdf(e) {clearTimeout(this.selectionTimer);// 捕獲鼠標坐標(相對視口)const mouseX = e.clientX;const mouseY = e.clientY;this.selectionTimer = setTimeout(() => {// 獲取 PDF iframe 的文檔對象const pdfWindow = this.$refs.pdfViewer.contentWindow;const pdfDocument = pdfWindow.document;// 計算 PDF 容器在頁面中的位置const iframeRect = this.$refs.pdfViewer.getBoundingClientRect();// console.log(mouseX, 'mouseX');// console.log(mouseY, 'mouseY');// console.log(iframeRect.left, 'iframeRect.left');// console.log(iframeRect.top, 'iframeRect.top');// console.log(pdfWindow.scrollX, 'pdfWindow.scrollX');// console.log(pdfWindow.scrollY, 'pdfWindow.scrollY');// console.log(window.scrollX, 'window.scrollX');// console.log(window.scrollY, 'window.scrollY');// 轉換坐標到 PDF 文檔坐標系const pdfX = mouseX;const pdfY = mouseY;// 在 PDF 文檔中檢測元素const targetElement = pdfDocument.elementFromPoint(pdfX, pdfY);const isValid = targetElement?.closest('#viewerContainer');// 其他驗證邏輯保持不變const selection = pdfWindow.getSelection();const isTextValid =selection.rangeCount > 0 &&!selection.isCollapsed &&selection.toString().trim().length >= 1;if (isValid && isTextValid) {// 使用鼠標坐標定位工具框const viewportX = mouseX + iframeRect.left;const viewportY = mouseY + iframeRect.top;this.updateToolPositionPdf(viewportX, viewportY);this.selectionToolsVisible = true;this.tempSelection = selection.toString();} else {this.selectionToolsVisible = false;}}, 50);},updateToolPositionPdf(absoluteX, absoluteY) {const tooltipWidth = ''; // 根據實際工具框寬度調整// 邊界檢測邏輯let finalLeft = absoluteX - 35;let finalTop = absoluteY - 62.7 - 20; // 減去按鈕元素高度 然后上移一點this.selectionPosition = {top: `${finalTop}px`,left: `${finalLeft}px`,maxWidth: `${tooltipWidth}px`,};console.log(this.selectionPosition);},

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

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

相關文章

生活電子常識-deepseek-r1本地化部署+ui界面搭建

前言 deepseek-r1 14b模型&#xff0c;32b模型部署在本地電腦上也能實現非常好的性能。 因此有興趣研究了下如何在本地部署。 同時最新流行mauns工作流&#xff0c;他們提供一句話實現網頁端任意應用的能力。實際上&#xff0c;你也可以用本地的模型來實現離線的ai工作流功能。…

mac絲滑安裝Windows操作系統【絲滑簡單免費】

mac絲滑安裝Windows操作系統【絲滑&簡單&免費】 記錄mac絲滑安裝windows系統1、安裝免費版 VMware fusion 132、安裝Windows鏡像文件3、跳過聯網安裝&#xff08;完成1后將2拖入1 點點點 即可來到3的環節&#xff09;4、 安裝vmware 工具【非常重要&#xff0c;涉及聯網…

基于Spring Boot的企業內管信息化系統的設計與實現(LW+源碼+講解)

專注于大學生項目實戰開發,講解,畢業答疑輔導&#xff0c;歡迎高校老師/同行前輩交流合作?。 技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;…

Pytorch實現之對稱卷積神經網絡結構實現超分辨率

簡介 簡介:針對傳統的超分辨率重建技術所重建的圖像過于光滑且缺乏細節的問題,作者提出了一種改進的生成對抗圖像超分辨率網絡。 該改進方法基于深度神經網絡,其生成模型包含多層卷積模塊和多層反卷積模塊,其中在感知損失基礎上增加了跳層連接和損失函數。 該判別模型由多…

Scikit-learn模型構建全流程解析:從數據預處理到超參數調優

模型選擇與訓練步驟及示例 1. 數據準備與探索 步驟說明&#xff1a;加載數據并初步探索其分布、缺失值、異常值等。 注意事項&#xff1a; 檢查數據類型&#xff08;數值/類別&#xff09;、缺失值和異常值。對類別型特征進行編碼&#xff08;如獨熱編碼&#xff09;。 實例&…

001-JMeter的安裝與配置

1.前期準備 下載好JMeter : https://jmeter.apache.org/download_jmeter.cgi 下載好JDK : :Java Downloads | Oracle 中國 下載圖中圈藍的JMeter和JDK就行&#xff0c;讓它邊下載&#xff0c;我們邊往下看 2.為什么要下載并安裝JDK ? JMeter 是基于 Java 開發的工具&#…

第2.2節 Android Jacoco插件覆蓋率采集

JaCoCo&#xff08;Java Code Coverage&#xff09;是一款開源的代碼覆蓋率分析工具&#xff0c;適用于Java和Android項目。它通過插樁技術統計測試過程中代碼的執行情況&#xff0c;生成可視化報告&#xff0c;幫助開發者評估測試用例的有效性。在github上開源的項目&#xff…

特征工程自動化(FeatureTools實戰)

目錄 特征工程自動化(FeatureTools實戰)1. 引言2. 項目背景與意義2.1 特征工程的重要性2.2 自動化特征工程的優勢2.3 工業級數據處理需求3. 數據集生成與介紹3.1 數據集構成3.2 數據生成方法4. 自動化特征工程理論基礎4.1 特征工程的基本概念4.2 FeatureTools庫簡介4.3 關鍵公…

Scikit-learn模型評估全流程解析:從數據劃分到交叉驗證優化

模型評估的步驟、scikit-learn函數及實例說明 1. 數據劃分&#xff08;Train-Test Split&#xff09; 函數&#xff1a;train_test_split使用場景&#xff1a;將數據分為訓練集和測試集&#xff0c;避免模型過擬合。作用&#xff1a;確保模型在未見過的數據上驗證性能。示例&…

Spring AI相關的面試題

以下是150道Spring AI相關的面試題目及答案&#xff1a; ### Spring AI基礎概念類 **1. 什么是Spring AI&#xff1f;** Spring AI是Spring框架的擴展&#xff0c;旨在簡化人工智能模型在Java應用中的集成與使用&#xff0c;提供與Spring生態無縫銜接的工具和抽象&#xff0c…

C++ 學習筆記(四)—— 類和對象

1、this指針 class Date { public&#xff1a;void Init(Date* this, int year, int month, int day){this->_year year;this->_month month;this->_day day;this->Print();// 這就是this指針&#xff0c;是編譯器自己加的&#xff0c;是用來讓成員函數找到成…

SpringMVC全局異常處理機制

異常處理機制 異常處理的兩種方式&#xff1a; 編程式異常處理&#xff1a;是指在代碼中顯式地編寫處理異常的邏輯。它通常涉及到對異常類型的檢測及其處理&#xff0c;例如使用 try-catch 塊來捕獲異常&#xff0c;然后在 catch 塊中編寫特定的處理代碼&#xff0c;或者在 f…

深入LangChain:LLM交互機制與RAG集成的技術

本文將聚焦于 LangChain 如何集成檢索增強生成&#xff08;RAG&#xff09;&#xff0c;了解其架構、主要組件&#xff0c;以及與 LLM 的交互 LangChain 架構概覽 1、基礎層 這是與各類 LLM 對接的 “橋梁”。LangChain 支持多種流行的 LLM&#xff0c;如 OpenAI 的系列模型、H…

本地部署 LangManus

本地部署 LangManus 0. 引言1. 部署 LangManus2. 部署 LangManus Web UI 0. 引言 LangManus 是一個社區驅動的 AI 自動化框架&#xff0c;它建立在開源社區的卓越工作基礎之上。我們的目標是將語言模型與專業工具&#xff08;如網絡搜索、爬蟲和 Python 代碼執行&#xff09;相…

SQL注入(SQL Injection)攻擊原理與防御措施

SQL是一種代碼注入技術&#xff0c;可使攻擊者修改應用程序向數據庫提供的查詢。 迄今為止&#xff0c;最常見和最嚴重的應用 程序安全威脅總是隱藏在與數據庫有某些連接的網絡應用 程序中。 通過這種 SQL 注入&#xff0c;攻擊者可以繞過登錄程序&#xff0c;獲取、更改甚至更…

【算法】十大排序算法(含時間復雜度、核心思想)

以下是 **十大經典排序算法** 的時間復雜度、空間復雜度及穩定性總結&#xff0c;適用于面試快速回顧&#xff1a;排序算法對比表 排序算法最佳時間復雜度平均時間復雜度最差時間復雜度空間復雜度穩定性核心思想冒泡排序O(n)O(n)O(n)O(1)穩定相鄰元素交換&#xff0c;大數沉底…

LVS的 NAT 模式實現 3 臺RS的輪詢訪問

使用LVS的 NAT 模式實現 3 臺RS的輪詢訪問 1.配置 RS&#xff08;NAT模式&#xff09;2. 配置 LVS 主機&#xff08;僅主機、NAT模式&#xff09;2.1 配置僅主機網卡&#xff08;192.168.66.150/24 VIP &#xff09;2.2 配置 NAT 網卡&#xff08;192.168.88.6/24 DIP&#xff…

一、MySQL8的my.ini文件

MySQL8.0.11的安裝版本my.ini配置文件默認存放在&#xff1a;C:/Program Files/MySQL/MySQL Server 8.0/ 目錄下&#xff1b;而MySQL8.0.11綠色免安裝版本是沒有my.ini配置文件&#xff0c;用戶可以自行構建后&#xff0c;再通過my.ini進行數據庫的相關配置 一、MySQL8.0.11默…

微調這件小事:訓練集中的輸入數據該作為instruction還是input?從LLaMA-Factory的源碼中尋找答案吧~

在之前的博文中,我們已經了解了LLaMA-Factory框架執行各類任務的流程。今天,我們將深入探討SFT微調過程中關于數據集的兩個關鍵問題: 數據集中的instruction和input是如何結合起來生成大模型可以理解的輸入的?instruction是不是就是system prompt呢?(之所以會問這個問題,…

nacos-actuator漏洞

1、nacos配置文件添加以下配置 vim application.properties# 添加以下配置項 management.endpoints.enabled-by-defaultfalse management.server.port-12、重啟Nacos systemctl restart nacos3、驗證 打開地址http://ip:port/nacos/actuator查看是否有敏感信息輸出&#xff0…