Electron PDF.js 预览文档问题解决

使用 electron 打包成 exe 安装文件后,PDF.js 自定义 viewer.html 预览 pdf 时,可能会出现预览路径加载不对的问题,还有右键复制功能无效的问题,都需要特殊处理

1. pdfjs 预览加载路径不对

直接使用浏览器内置的 pdf 阅读器预览,无论是在线网站运行,还是 electron 打包后,预览均没有问题,缺点是页面无法自定义,不够灵活。

使用 pdfjs 自定义页面 viewer.html 预览,网站运行时,没有问题

但是 electron 打包后,pdf 加载路径就不对了,有跨域问题,electron开发好难搞呀

1.1 网站在线运行

jsx 复制代码
<iframe
  title="预览文档"
  src="/web/mViewer.html?file=../pdf/15.pdf"
  width="100%"
  height="100%"
></iframe>

在线运行时,本地启动服务地址为http://localhost:3000

pdf 文档预览调用链,如下所示:

http://localhost:3000/web/mViewer.html?file=../pdf/15.pdf

-> http://localhost:3000/pdf/15.pdf

控制台显示如下:

1.2 electron 打包后运行

使用 electron 打包后,pdfjs 加载离线的 pdf 文件就会报错

报错信息如下所示:

Request URL: file:///web/mViewer.html?file=../pdf/15.pdf

Referrer Policy: no-referrer

解决方案:在 iframe 标签的 src 属性中使用相对路径或者绝对路径链接到 pdfjs 的相关资源。

我使用了process.env.PUBLIC_URL,增加了referrerPolicy="no-referrer"配置,确保在打包编译后生成的文件中,相关资源能够正确加载。

配置了之后,在线运行也是没问题的。

jsx 复制代码
<iframe
  ref={iframeRef}
  title="预览文档"
  src={`${process.env.PUBLIC_URL}/web/mViewer.html?file=${
    "." + curSubmenu.pdfPath
  }#page=${curSubmenu.pdfStartPage}`}
  width="100%"
  height="100%"
  referrerPolicy="no-referrer"
></iframe>

更改配置后,electron 中 pdf 文档预览时,加载路径如下所示:

2. pdfjs 右键复制功能

网站运行时,pdf 文档预览,可以选中文本,然后右键复制

也可以选中后,用 ctrl+c 快捷键复制,这是浏览器自带的功能。

但是使用 electron 打包后,选中pdf文本后,默认右键是没有功能的

需要自己处理右键菜单,要在main.js中添加复制功能,如下所示:

js 复制代码
const { Menu, MenuItem } = require("electron");

// 创建上下文菜单
const contextMenu = new Menu();
contextMenu.append(
  new MenuItem({
    label: "复制",
    role: "copy",
  })
);

// 在 PDF 预览窗口上绑定上下文菜单
win.webContents.on("context-menu", (e, params) => {
  contextMenu.popup(win, params.x, params.y);
});

展示效果如下图所示:

3. 复制当前 pdf 页文本

项目要求,需要自定义按钮实现复制当前 pdf 页文本内容,目前插件是不支持的。

我的实现方案是,获取到页码和页面元素,使用textContent属性获取文本内容

直接查看源码,获取对应元素,如下所示:

data-page-number=11中的11可以替换成变量

js 复制代码
// 定义iframe元素
const iframeRef = useRef < HTMLIFrameElement > null;

// 复制方法
function handleCopy() {
    if (iframe?.contentDocument) {
        // 获取dom元素
        const document = iframe.contentDocument;
        // 获取当前页码元素
        const pageNumberEle = document.getElementById(
          "pageNumber"
        ) as HTMLInputElement;
        // 获取当前页码
        const pageNumber = pageNumberEle.value;
        // 获取当前页元素
        const page = document.querySelector('.page[data-page-number=11]');
        // 获取当前页文本内容
        const textContent = page?.querySelector(".textLayer")?.textContent || "";
        // 复制到剪切板的代码
        console.log("textContent", textContent);
        // 将选定的文本保存到剪贴板
        navigator.clipboard.writeText(textContent);
    }
}
相关推荐
我要洋人死1 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人1 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人1 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR1 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
小牛itbull3 小时前
ReactPress:重塑内容管理的未来
react.js·github·reactpress