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);
    }
}
相关推荐
用户938515635074 小时前
写了这么久 useState,你真的知道它在干什么吗?
前端·javascript
慢功夫4 小时前
💡第七篇:VSCode语言服务中,代码跳转和诊断是怎么做的?
前端·visual studio code
Csvn4 小时前
✨ TypeScript `satisfies` 操作符实战——5 个让代码更「聪明」的生产场景
前端
Healer9184 小时前
vue3页面缓存-keepAlive
前端
一个有理想的摸鱼选手4 小时前
在三维地球上以另一种视角感受巴威台风
前端·gis·ai编程
程序员黑豆5 小时前
鸿蒙应用开发:Grid组件实现九宫格布局教程
前端·华为·harmonyos
浮江雾5 小时前
Flutter第十七节-----路由管理(3)
android·开发语言·前端·javascript·flutter·入门
阿懂在掘金5 小时前
企业级命令式弹窗方案:三行代码适配已有 Dialog
前端·vue.js·前端框架
Revolution615 小时前
测试接口为什么进了生产包:前端环境变量到底在什么时候生效
前端·前端工程化
午安~婉5 小时前
Git中SSH连接
前端·git·gitee